neo4j-core 8.1.4 → 9.0.0.alpha.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.
Files changed (59) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +71 -8
  3. data/lib/neo4j-core.rb +3 -49
  4. data/lib/neo4j/core.rb +4 -0
  5. data/lib/neo4j/core/config.rb +13 -0
  6. data/lib/neo4j/core/cypher_session/adaptors.rb +15 -15
  7. data/lib/neo4j/core/cypher_session/adaptors/bolt.rb +39 -48
  8. data/lib/neo4j/core/cypher_session/adaptors/bolt/chunk_writer_io.rb +0 -4
  9. data/lib/neo4j/core/cypher_session/adaptors/bolt/pack_stream.rb +7 -3
  10. data/lib/neo4j/core/cypher_session/adaptors/embedded.rb +1 -2
  11. data/lib/neo4j/core/cypher_session/adaptors/has_uri.rb +4 -0
  12. data/lib/neo4j/core/cypher_session/adaptors/http.rb +1 -3
  13. data/lib/neo4j/core/cypher_session/responses.rb +1 -1
  14. data/lib/neo4j/core/cypher_session/responses/bolt.rb +0 -17
  15. data/lib/neo4j/core/cypher_session/responses/embedded.rb +9 -7
  16. data/lib/neo4j/core/cypher_session/responses/http.rb +3 -4
  17. data/lib/neo4j/core/cypher_session/transactions.rb +2 -0
  18. data/lib/{neo4j-core → neo4j/core}/helpers.rb +1 -14
  19. data/lib/neo4j/core/logging.rb +44 -0
  20. data/lib/{neo4j-core → neo4j/core}/query.rb +7 -6
  21. data/lib/{neo4j-core → neo4j/core}/query_clauses.rb +9 -16
  22. data/lib/{neo4j-core → neo4j/core}/query_find_in_batches.rb +3 -5
  23. data/lib/{neo4j-core → neo4j/core}/version.rb +1 -1
  24. data/lib/neo4j/transaction.rb +6 -8
  25. data/neo4j-core.gemspec +13 -11
  26. metadata +46 -50
  27. data/lib/ext/kernel.rb +0 -9
  28. data/lib/neo4j-core/active_entity.rb +0 -11
  29. data/lib/neo4j-core/label.rb +0 -9
  30. data/lib/neo4j-embedded.rb +0 -16
  31. data/lib/neo4j-embedded/cypher_response.rb +0 -71
  32. data/lib/neo4j-embedded/embedded_database.rb +0 -26
  33. data/lib/neo4j-embedded/embedded_ha_session.rb +0 -30
  34. data/lib/neo4j-embedded/embedded_impermanent_session.rb +0 -17
  35. data/lib/neo4j-embedded/embedded_label.rb +0 -88
  36. data/lib/neo4j-embedded/embedded_node.rb +0 -206
  37. data/lib/neo4j-embedded/embedded_relationship.rb +0 -77
  38. data/lib/neo4j-embedded/embedded_session.rb +0 -203
  39. data/lib/neo4j-embedded/embedded_transaction.rb +0 -30
  40. data/lib/neo4j-embedded/label.rb +0 -66
  41. data/lib/neo4j-embedded/property.rb +0 -106
  42. data/lib/neo4j-embedded/to_java.rb +0 -44
  43. data/lib/neo4j-server.rb +0 -12
  44. data/lib/neo4j-server/cypher_label.rb +0 -35
  45. data/lib/neo4j-server/cypher_node.rb +0 -221
  46. data/lib/neo4j-server/cypher_relationship.rb +0 -142
  47. data/lib/neo4j-server/cypher_response.rb +0 -248
  48. data/lib/neo4j-server/cypher_session.rb +0 -263
  49. data/lib/neo4j-server/cypher_transaction.rb +0 -100
  50. data/lib/neo4j-server/label.rb +0 -40
  51. data/lib/neo4j-server/resource.rb +0 -57
  52. data/lib/neo4j/entity_equality.rb +0 -8
  53. data/lib/neo4j/entity_marshal.rb +0 -20
  54. data/lib/neo4j/label.rb +0 -90
  55. data/lib/neo4j/node.rb +0 -216
  56. data/lib/neo4j/property_container.rb +0 -17
  57. data/lib/neo4j/property_validator.rb +0 -22
  58. data/lib/neo4j/relationship.rb +0 -161
  59. data/lib/neo4j/session.rb +0 -222
@@ -1,142 +0,0 @@
1
- module Neo4j
2
- module Server
3
- class CypherRelationship < Neo4j::Relationship
4
- include Neo4j::Server::Resource
5
- include Neo4j::Core::ActiveEntity
6
-
7
- MARSHAL_INSTANCE_VARIABLES = %i[@rel_type @props @start_node_neo_id @end_node_neo_id @id]
8
-
9
- def initialize(session, value)
10
- @session = session
11
- @response_hash = value
12
- @rel_type = @response_hash[:type]
13
- @props = @response_hash[:data]
14
- @start_node_neo_id = neo_id_integer(@response_hash[:start])
15
- @end_node_neo_id = neo_id_integer(@response_hash[:end])
16
- @id = @response_hash[:id]
17
- end
18
-
19
- def ==(other)
20
- other.class == self.class && other.neo_id == neo_id
21
- end
22
- alias eql? ==
23
-
24
- attr_reader :id
25
-
26
- def neo_id
27
- id
28
- end
29
-
30
- def inspect
31
- "CypherRelationship #{neo_id}"
32
- end
33
-
34
- def load_resource
35
- return if resource_data_present?
36
-
37
- @resource_data = @session._query_or_fail("#{match_start} RETURN n", true, neo_id: neo_id) # r.first_data
38
- end
39
-
40
- attr_reader :start_node_neo_id
41
-
42
- attr_reader :end_node_neo_id
43
-
44
- def _start_node_id
45
- @start_node_neo_id ||= get_node_id(:start)
46
- end
47
-
48
- def _end_node_id
49
- @end_node_neo_id ||= get_node_id(:end)
50
- end
51
-
52
- def _start_node
53
- @_start_node ||= Neo4j::Node._load(start_node_neo_id)
54
- end
55
-
56
- def _end_node
57
- load_resource
58
- @_end_node ||= Neo4j::Node._load(end_node_neo_id)
59
- end
60
-
61
- def get_node_id(direction)
62
- load_resource
63
- resource_url_id(resource_url(direction))
64
- end
65
-
66
- def get_property(key)
67
- @session._query_or_fail("#{match_start} RETURN n.`#{key}`", true, neo_id: neo_id)
68
- end
69
-
70
- def set_property(key, value)
71
- @session._query_or_fail("#{match_start} SET n.`#{key}` = {value}", false, value: value, neo_id: neo_id)
72
- end
73
-
74
- def remove_property(key)
75
- @session._query_or_fail("#{match_start} REMOVE n.`#{key}`", false, neo_id: neo_id)
76
- end
77
-
78
- # (see Neo4j::Relationship#props)
79
- def props
80
- if @props
81
- @props
82
- else
83
- hash = @session._query_entity_data("#{match_start} RETURN n", nil, neo_id: neo_id)
84
- @props = Hash[hash[:data].map { |k, v| [k, v] }]
85
- end
86
- end
87
-
88
- # (see Neo4j::Relationship#props=)
89
- def props=(properties)
90
- @session._query_or_fail("#{match_start} SET n = { props }", false, props: properties, neo_id: neo_id)
91
- properties
92
- end
93
-
94
- # (see Neo4j::Relationship#update_props)
95
- def update_props(properties)
96
- return if properties.empty?
97
-
98
- params = {}
99
- q = "#{match_start} SET " + properties.keys.each_with_index.map do |k, _i|
100
- param = k.to_s.tr_s('^a-zA-Z0-9', '_').gsub(/^_+|_+$/, '')
101
- params[param] = properties[k]
102
-
103
- "n.`#{k}`= {#{param}}"
104
- end.join(',')
105
-
106
- @session._query_or_fail(q, false, params.merge(neo_id: neo_id))
107
-
108
- properties
109
- end
110
-
111
- def rel_type
112
- @rel_type.to_sym
113
- end
114
-
115
- def del
116
- @session._query("#{match_start} DELETE n", neo_id: neo_id)
117
- end
118
- alias delete del
119
- alias destroy del
120
-
121
- def exist?
122
- response = @session._query("#{match_start} RETURN n", neo_id: neo_id)
123
- # binding.pry
124
- (response.data.nil? || response.data.empty?) ? false : true
125
- end
126
-
127
- private
128
-
129
- def match_start(identifier = 'n')
130
- "MATCH (node)-[#{identifier}]-() WHERE ID(#{identifier}) = {neo_id}"
131
- end
132
-
133
- def resource_data_present?
134
- !resource_data.nil? && !resource_data.empty?
135
- end
136
-
137
- def neo_id_integer(id_or_url)
138
- id_or_url.is_a?(Integer) ? id_or_url : id_or_url.split('/').last.to_i
139
- end
140
- end
141
- end
142
- end
@@ -1,248 +0,0 @@
1
- module Neo4j
2
- module Server
3
- class CypherResponse
4
- attr_reader :data, :columns, :error_msg, :error_status, :error_code, :response
5
-
6
- class ResponseError < StandardError
7
- attr_reader :status, :code
8
-
9
- def initialize(msg, status, code)
10
- super(msg)
11
- @status = status
12
- @code = code
13
- end
14
- end
15
-
16
- class ConstraintViolationError < ResponseError; end
17
-
18
- class HashEnumeration
19
- include Enumerable
20
- extend Forwardable
21
- def_delegator :@response, :error_msg
22
- def_delegator :@response, :error_status
23
- def_delegator :@response, :error_code
24
- def_delegator :@response, :columns
25
- def_delegator :@response, :struct
26
-
27
- def initialize(response, query)
28
- @response = response
29
- @query = query
30
- end
31
-
32
- def to_s
33
- @query
34
- end
35
-
36
- def inspect
37
- "Enumerable query: '#{@query}'"
38
- end
39
-
40
- def each
41
- @response.each_data_row { |row| yield struct_rows(row) }
42
- end
43
-
44
- def struct_rows(row)
45
- struct.new.tap do |result|
46
- row.each_with_index { |value, i| result[columns[i]] = value }
47
- end
48
- end
49
- end
50
-
51
- EMPTY_STRING = ''
52
- def to_struct_enumeration(cypher = EMPTY_STRING)
53
- HashEnumeration.new(self, cypher)
54
- end
55
-
56
- def to_node_enumeration(cypher = EMPTY_STRING, session = Neo4j::Session.current)
57
- Enumerator.new do |yielder|
58
- to_struct_enumeration(cypher).each do |row|
59
- yielder << row_pair_in_struct(row, session)
60
- end
61
- end
62
- end
63
-
64
- def row_pair_in_struct(row, session)
65
- @struct.new.tap do |result|
66
- row.each_pair do |column, value|
67
- result[column] = map_row_value(value, session)
68
- end
69
- end
70
- end
71
-
72
- def map_row_value(value, session)
73
- if value.is_a?(Hash) && looks_like_an_object?(value)
74
- hash_value_as_object(value, session)
75
- elsif value.is_a?(Array)
76
- value.map! { |v| map_row_value(v, session) }
77
- else
78
- value
79
- end
80
- end
81
-
82
- def hash_value_as_object(value, session)
83
- return value unless %i[node relationship].include?(identify_entity(value))
84
- add_entity_id(value)
85
-
86
- basic_obj = (node?(value) ? CypherNode : CypherRelationship).new(session, value)
87
- unwrapped? ? basic_obj : basic_obj.wrapper
88
- end
89
-
90
- def identify_entity(data)
91
- self_string = data[:self]
92
- if self_string
93
- if self_string.include?('node')
94
- :node
95
- elsif self_string.include?('relationship')
96
- :relationship
97
- end
98
- elsif %i[nodes relationships start end length].all? { |k| data.key?(k) }
99
- :path
100
- end
101
- end
102
-
103
- def looks_like_an_object?(value)
104
- value[:labels] || value[:type]
105
- end
106
-
107
- def unwrapped!
108
- @_unwrapped_obj = true
109
- end
110
-
111
- def unwrapped?
112
- !!@_unwrapped_obj
113
- end
114
-
115
- def node?(value)
116
- value[:labels]
117
- end
118
-
119
- attr_reader :struct
120
-
121
- def initialize(response, uncommited = false)
122
- @response = response
123
- @uncommited = uncommited
124
- end
125
-
126
- def entity_data(id = nil)
127
- if @uncommited
128
- data = @data.first[:row].first
129
- data.is_a?(Hash) ? {data: data, id: id} : data
130
- else
131
- data = @data[0][0]
132
- data.is_a?(Hash) ? add_entity_id(data) : data
133
- end
134
- end
135
-
136
- def first_data
137
- if @uncommited
138
- @data.first[:row].first
139
- else
140
- data = @data[0][0]
141
- data.is_a?(Hash) ? add_entity_id(data) : data
142
- end
143
- end
144
-
145
- def add_entity_id(data)
146
- data[:id] = if data[:metadata] && data[:metadata][:id]
147
- data[:metadata][:id]
148
- else
149
- data[:self].split('/')[-1].to_i
150
- end
151
- data
152
- end
153
-
154
- def error?
155
- !!@error
156
- end
157
-
158
- def raise_if_cypher_error!
159
- raise_cypher_error if error?
160
- end
161
-
162
- RETRYABLE_ERROR_STATUSES = %w[DeadlockDetectedException AcquireLockTimeoutException ExternalResourceFailureException UnknownFailureException]
163
- def retryable_error?
164
- return unless error?
165
- RETRYABLE_ERROR_STATUSES.include?(@error_status)
166
- end
167
-
168
- def data?
169
- !response.body[:data].nil?
170
- end
171
-
172
- def raise_unless_response_code(code)
173
- fail "Response code #{response.status}, expected #{code} for #{response.headers[:location]}, #{response.body}" unless response.status == code
174
- end
175
-
176
- def each_data_row
177
- data.each do |r|
178
- yieldable = if @uncommitted
179
- r[:row]
180
- else
181
- transaction_row?(r) ? r[:rest] : r
182
- end
183
- yield yieldable
184
- end
185
- end
186
-
187
- def transaction_response?
188
- response.respond_to?(:body) && !response.body[:commit].nil?
189
- end
190
-
191
- def set_data(response)
192
- @data = response[:data]
193
- @columns = response[:columns]
194
- @struct = @columns.empty? ? Object.new : Struct.new(*@columns.map(&:to_sym))
195
- self
196
- end
197
-
198
- def set_error(error)
199
- @error = true
200
- @error_msg = error[:message]
201
- @error_status = error[:status] || error[:exception] || error[:code]
202
- @error_code = error[:code] || error[:fullname]
203
- self
204
- end
205
-
206
- CONSTRAINT_ERROR = 'Neo.ClientError.Schema.ConstraintViolation'
207
- def raise_error
208
- fail 'Tried to raise error without an error' unless @error
209
- error_class = constraint_error? ? ConstraintViolationError : ResponseError
210
- fail error_class.new(@error_msg, @error_status, @error_code)
211
- end
212
-
213
- def constraint_error?
214
- @error_code == CONSTRAINT_ERROR || (@error_msg || '').include?('already exists with')
215
- end
216
-
217
- def raise_cypher_error
218
- fail 'Tried to raise error without an error' unless @error
219
- fail Neo4j::Session::CypherError.new(@error_msg, @error_code, @error_status)
220
- end
221
-
222
-
223
- def self.create_with_no_tx(response)
224
- case response.status
225
- when 200 then new(response).set_data(response.body)
226
- when 400 then new(response).set_error(response.body)
227
- else
228
- fail "Unknown response code #{response.status} for #{response.env[:url]}"
229
- end
230
- end
231
-
232
- def self.create_with_tx(response)
233
- fail "Unknown response code #{response.status} for #{response.request_uri}" unless response.status == 200
234
-
235
- new(response, true).tap do |cr|
236
- body = response.body
237
- body[:errors].empty? ? cr.set_data(body[:results].first) : cr.set_error(body[:errors].first)
238
- end
239
- end
240
-
241
- private
242
-
243
- def transaction_row?(row)
244
- row.is_a?(Hash) && row[:rest] && row[:row]
245
- end
246
- end
247
- end
248
- end
@@ -1,263 +0,0 @@
1
- require 'uri'
2
-
3
- module Neo4j
4
- module Server
5
- Neo4j::Session.register_db(:server_db) do |endpoint_url, url_opts|
6
- Neo4j::Server::CypherSession.open(endpoint_url, url_opts)
7
- end
8
-
9
- class CypherSession < Neo4j::Session
10
- include Resource
11
-
12
- alias super_query query
13
- attr_reader :connection
14
-
15
- def initialize(data_url, connection)
16
- @connection = connection
17
- Neo4j::Session.register(self)
18
- initialize_resource(data_url)
19
- Neo4j::Session._notify_listeners(:session_available, self)
20
- end
21
-
22
- # @param [Hash] params could be empty or contain basic authentication user and password
23
- # @return [Faraday]
24
- # @see https://github.com/lostisland/faraday
25
- def self.create_connection(params, url = nil)
26
- init_params = params[:initialize] && params.delete(:initialize)
27
- conn = Faraday.new(url, init_params) do |b|
28
- b.request :basic_auth, params[:basic_auth][:username], params[:basic_auth][:password] if params[:basic_auth]
29
- b.request :multi_json
30
- # b.response :logger, ::Logger.new(STDOUT), bodies: true
31
-
32
- b.response :multi_json, symbolize_keys: true, content_type: 'application/json'
33
- # b.use Faraday::Response::RaiseError
34
- require 'typhoeus'
35
- require 'typhoeus/adapters/faraday'
36
- b.adapter :typhoeus
37
- # b.adapter Faraday.default_adapter
38
- end
39
- conn.headers = {'Content-Type' => 'application/json', 'User-Agent' => ::Neo4j::Session.user_agent_string}
40
- conn
41
- end
42
-
43
- # Opens a session to the database
44
- # @see Neo4j::Session#open
45
- #
46
- # @param [String] endpoint_url - the url to the neo4j server, defaults to 'http://localhost:7474'
47
- # @param [Hash] params faraday params, see #create_connection or an already created faraday connection
48
- def self.open(endpoint_url = nil, params = {})
49
- extract_basic_auth(endpoint_url, params)
50
- url = endpoint_url || 'http://localhost:7474'
51
- connection = params[:connection] || create_connection(params, url)
52
- response = connection.get(url)
53
- fail "Server not available on #{url} (response code #{response.status})" unless response.status == 200
54
- establish_session(response.body, connection)
55
- end
56
-
57
- def self.establish_session(root_data, connection)
58
- data_url = root_data[:data]
59
- data_url << '/' unless data_url.nil? || data_url.end_with?('/')
60
- CypherSession.new(data_url, connection)
61
- end
62
-
63
- def self.extract_basic_auth(url, params)
64
- return unless url && URI(url).userinfo
65
- params[:basic_auth] = {username: URI(url).user, password: URI(url).password}
66
- end
67
-
68
- private_class_method :extract_basic_auth
69
-
70
- def db_type
71
- :server_db
72
- end
73
-
74
- def to_s
75
- "#{self.class} url: '#{@resource_url}'"
76
- end
77
-
78
- def inspect
79
- "#{self} version: '#{version}'"
80
- end
81
-
82
- def version
83
- resource_data ? resource_data[:neo4j_version] : ''
84
- end
85
-
86
- def initialize_resource(data_url)
87
- response = @connection.get(data_url)
88
- expect_response_code!(response, 200)
89
- data_resource = response.body
90
- fail "No data_resource for #{response.body}" unless data_resource
91
- # store the resource data
92
- init_resource_data(data_resource, data_url)
93
- end
94
-
95
- def self.transaction_class
96
- Neo4j::Server::CypherTransaction
97
- end
98
-
99
- # Duplicate of CypherSession::Adaptor::Base#transaction
100
- def transaction
101
- return self.class.transaction_class.new(self) if !block_given?
102
-
103
- begin
104
- tx = transaction
105
-
106
- yield tx
107
- rescue Exception => e # rubocop:disable Lint/RescueException
108
- tx.mark_failed
109
-
110
- raise e
111
- ensure
112
- tx.close
113
- end
114
- end
115
-
116
- def create_node(props = nil, labels = [])
117
- label_string = labels.empty? ? '' : (':' + labels.map { |k| "`#{k}`" }.join(':'))
118
- if !props.nil?
119
- prop = '{props}'
120
- props.each_key { |k| props.delete(k) if props[k].nil? }
121
- end
122
-
123
- id = _query_or_fail("CREATE (n#{label_string} #{prop}) RETURN ID(n)", true, props: props)
124
- CypherNode.new(self, props.nil? ? id : {id: id, metadata: {labels: labels}, data: props})
125
- end
126
-
127
- def load_node(neo_id)
128
- query.unwrapped.match(:n).where(n: {neo_id: neo_id}).pluck(:n).first
129
- end
130
-
131
- def load_relationship(neo_id)
132
- query.unwrapped.optional_match('(n)-[r]-()').where(r: {neo_id: neo_id}).pluck(:r).first
133
- rescue Neo4j::Session::CypherError => cypher_error
134
- return nil if cypher_error.message =~ /not found$/
135
-
136
- raise cypher_error
137
- end
138
-
139
- def create_label(name)
140
- CypherLabel.new(self, name)
141
- end
142
-
143
- def uniqueness_constraints(label)
144
- schema_properties("/db/data/schema/constraint/#{label}/uniqueness")
145
- end
146
-
147
- def indexes(label)
148
- schema_properties("/db/data/schema/index/#{label}")
149
- end
150
-
151
- def schema_properties(query_string)
152
- response = @connection.get(query_string)
153
- expect_response_code!(response, 200)
154
- {property_keys: response.body.map! { |row| row[:property_keys].map(&:to_sym) }}
155
- end
156
-
157
- def find_all_nodes(label_name)
158
- search_result_to_enumerable_first_column(_query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)"))
159
- end
160
-
161
- def find_nodes(label_name, key, value)
162
- value = "'#{value}'" if value.is_a? String
163
-
164
- response = _query_or_fail("MATCH (n:`#{label_name}`) WHERE n.#{key} = #{value} RETURN ID(n)")
165
- search_result_to_enumerable_first_column(response)
166
- end
167
-
168
- def query(*args)
169
- if [[String], [String, Hash]].include?(args.map(&:class))
170
- response = _query(*args)
171
- response.raise_error if response.error?
172
- response.to_node_enumeration(args[0])
173
- else
174
- options = args[0] || {}
175
- Neo4j::Core::Query.new(options.merge(session: self))
176
- end
177
- end
178
-
179
- def _query_data(query)
180
- r = _query_or_fail(query, true)
181
- Neo4j::Transaction.current ? r : r[:data]
182
- end
183
-
184
- DEFAULT_RETRY_COUNT = ENV['NEO4J_RETRY_COUNT'].nil? ? 10 : ENV['NEO4J_RETRY_COUNT'].to_i
185
-
186
- def _query_or_fail(query, single_row = false, params = {}, retry_count = DEFAULT_RETRY_COUNT)
187
- query, params = query_and_params(query, params)
188
-
189
- response = _query(query, params)
190
- if response.error?
191
- _retry_or_raise(query, params, single_row, retry_count, response)
192
- else
193
- single_row ? response.first_data : response
194
- end
195
- end
196
-
197
- def query_and_params(query_or_query_string, params)
198
- if query_or_query_string.is_a?(::Neo4j::Core::Query)
199
- cypher = query_or_query_string.to_cypher
200
- [cypher, query_or_query_string.send(:merge_params).merge(params)]
201
- else
202
- [query_or_query_string, params]
203
- end
204
- end
205
-
206
- def _retry_or_raise(query, params, single_row, retry_count, response)
207
- response.raise_error unless response.retryable_error?
208
- retry_count > 0 ? _query_or_fail(query, single_row, params, retry_count - 1) : response.raise_error
209
- end
210
-
211
- def _query_entity_data(query, id = nil, params = {})
212
- _query(query, params).tap(&:raise_if_cypher_error!).entity_data(id)
213
- end
214
-
215
- def _query(query, params = {}, options = {})
216
- query, params = query_and_params(query, params)
217
-
218
- ActiveSupport::Notifications.instrument('neo4j.cypher_query', params: params, context: options[:context],
219
- cypher: query, pretty_cypher: options[:pretty_cypher]) do
220
- if current_transaction
221
- current_transaction._query(query, params)
222
- else
223
- query = params.nil? ? {'query' => query} : {'query' => query, 'params' => params}
224
- response = @connection.post(resource_url(:cypher), query)
225
- CypherResponse.create_with_no_tx(response)
226
- end
227
- end
228
- end
229
-
230
- def search_result_to_enumerable_first_column(response)
231
- return [] unless response.data
232
-
233
- Enumerator.new do |yielder|
234
- response.data.each do |data|
235
- if current_transaction
236
- data[:row].each do |id|
237
- yielder << CypherNode.new(self, id).wrapper
238
- end
239
- else
240
- yielder << CypherNode.new(self, data[0]).wrapper
241
- end
242
- end
243
- end
244
- end
245
-
246
- def current_transaction
247
- Neo4j::Transaction.current_for(self)
248
- end
249
-
250
- EMPTY = ''
251
- NEWLINE_W_SPACES = "\n "
252
- def self.log_with
253
- ActiveSupport::Notifications.subscribe('neo4j.cypher_query') do |_, start, finish, _id, payload|
254
- ms = (finish - start) * 1000
255
- params_string = (payload[:params] && !payload[:params].empty? ? "| #{payload[:params].inspect}" : EMPTY)
256
- cypher = payload[:pretty_cypher] ? NEWLINE_W_SPACES + payload[:pretty_cypher].gsub(/\n/, NEWLINE_W_SPACES) : payload[:cypher]
257
-
258
- yield(" #{ANSI::CYAN}#{payload[:context] || 'CYPHER'}#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR} #{cypher} #{params_string}")
259
- end
260
- end
261
- end
262
- end
263
- end