neo4j-core 3.1.1 → 4.0.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +7 -12
  3. data/README.md +7 -7
  4. data/lib/neo4j-core.rb +3 -2
  5. data/lib/neo4j-core/active_entity.rb +8 -10
  6. data/lib/neo4j-core/cypher_translator.rb +61 -59
  7. data/lib/neo4j-core/hash_with_indifferent_access.rb +31 -22
  8. data/lib/neo4j-core/helpers.rb +15 -17
  9. data/lib/neo4j-core/label.rb +7 -6
  10. data/lib/neo4j-core/query.rb +271 -268
  11. data/lib/neo4j-core/query_clauses.rb +371 -355
  12. data/lib/neo4j-core/query_find_in_batches.rb +26 -26
  13. data/lib/neo4j-core/version.rb +1 -1
  14. data/lib/neo4j-embedded.rb +2 -2
  15. data/lib/neo4j-embedded/cypher_response.rb +40 -41
  16. data/lib/neo4j-embedded/embedded_database.rb +21 -22
  17. data/lib/neo4j-embedded/embedded_ha_session.rb +13 -11
  18. data/lib/neo4j-embedded/embedded_impermanent_session.rb +9 -8
  19. data/lib/neo4j-embedded/embedded_label.rb +64 -70
  20. data/lib/neo4j-embedded/embedded_node.rb +68 -73
  21. data/lib/neo4j-embedded/embedded_relationship.rb +6 -13
  22. data/lib/neo4j-embedded/embedded_session.rb +128 -132
  23. data/lib/neo4j-embedded/embedded_transaction.rb +34 -33
  24. data/lib/neo4j-embedded/property.rb +84 -77
  25. data/lib/neo4j-embedded/to_java.rb +24 -23
  26. data/lib/neo4j-server.rb +1 -1
  27. data/lib/neo4j-server/cypher_authentication.rb +105 -103
  28. data/lib/neo4j-server/cypher_label.rb +25 -23
  29. data/lib/neo4j-server/cypher_node.rb +180 -177
  30. data/lib/neo4j-server/cypher_node_uncommited.rb +11 -9
  31. data/lib/neo4j-server/cypher_relationship.rb +101 -102
  32. data/lib/neo4j-server/cypher_response.rb +171 -170
  33. data/lib/neo4j-server/cypher_session.rb +209 -205
  34. data/lib/neo4j-server/cypher_transaction.rb +66 -48
  35. data/lib/neo4j-server/resource.rb +17 -22
  36. data/lib/neo4j/entity_equality.rb +3 -4
  37. data/lib/neo4j/label.rb +13 -16
  38. data/lib/neo4j/node.rb +30 -34
  39. data/lib/neo4j/property_container.rb +3 -3
  40. data/lib/neo4j/property_validator.rb +4 -5
  41. data/lib/neo4j/relationship.rb +17 -22
  42. data/lib/neo4j/session.rb +19 -21
  43. data/lib/neo4j/tasks/config_server.rb +2 -3
  44. data/lib/neo4j/tasks/neo4j_server.rake +82 -74
  45. data/lib/neo4j/transaction.rb +23 -22
  46. data/neo4j-core.gemspec +21 -16
  47. metadata +72 -2
@@ -1,253 +1,257 @@
1
- module Neo4j::Server
2
-
3
- # Plugin
4
- Neo4j::Session.register_db(:server_db) do |*url_opts|
5
- Neo4j::Server::CypherSession.open(*url_opts)
6
- end
1
+ module Neo4j
2
+ module Server
3
+ # Plugin
4
+ Neo4j::Session.register_db(:server_db) do |*url_opts|
5
+ Neo4j::Server::CypherSession.open(*url_opts)
6
+ end
7
7
 
8
- class CypherSession < Neo4j::Session
9
- include Resource
10
- include Neo4j::Core::CypherTranslator
8
+ class CypherSession < Neo4j::Session
9
+ include Resource
10
+ include Neo4j::Core::CypherTranslator
11
11
 
12
- alias_method :super_query, :query
13
- attr_reader :connection, :auth
12
+ alias_method :super_query, :query
13
+ attr_reader :connection, :auth
14
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
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
22
22
 
23
- # @param [Hash] params could be empty or contain basic authentication user and password
24
- # @return [Faraday]
25
- # @see https://github.com/lostisland/faraday
26
- def self.create_connection(params)
27
- init_params = params[:initialize] and params.delete(:initialize)
28
- conn = Faraday.new(init_params) do |b|
29
- b.request :basic_auth, params[:basic_auth][:username], params[:basic_auth][:password] if params[:basic_auth]
30
- b.request :json
31
- #b.response :logger
32
- b.response :json, :content_type => "application/json"
33
- #b.use Faraday::Response::RaiseError
34
- b.use Faraday::Adapter::NetHttpPersistent
35
- # b.adapter Faraday.default_adapter
36
- end
37
- conn.headers = { 'Content-Type' => 'application/json', 'User-Agent' => ::Neo4j::Session.user_agent_string }
38
- conn
39
- end
23
+ # @param [Hash] params could be empty or contain basic authentication user and password
24
+ # @return [Faraday]
25
+ # @see https://github.com/lostisland/faraday
26
+ def self.create_connection(params)
27
+ init_params = params[:initialize] && params.delete(:initialize)
28
+ conn = Faraday.new(init_params) do |b|
29
+ b.request :basic_auth, params[:basic_auth][:username], params[:basic_auth][:password] if params[:basic_auth]
30
+ b.request :json
31
+ # b.response :logger
32
+ b.response :json, content_type: 'application/json'
33
+ # b.use Faraday::Response::RaiseError
34
+ b.use Faraday::Adapter::NetHttpPersistent
35
+ # b.adapter Faraday.default_adapter
36
+ end
37
+ conn.headers = {'Content-Type' => 'application/json', 'User-Agent' => ::Neo4j::Session.user_agent_string}
38
+ conn
39
+ end
40
40
 
41
- # Opens a session to the database
42
- # @see Neo4j::Session#open
43
- #
44
- # @param [String] endpoint_url - the url to the neo4j server, defaults to 'http://localhost:7474'
45
- # @param [Hash] params faraday params, see #create_connection or an already created faraday connection
46
- def self.open(endpoint_url = nil, params = {})
47
- extract_basic_auth(endpoint_url, params)
48
- connection = params[:connection] || create_connection(params)
49
- url = endpoint_url || 'http://localhost:7474'
50
- auth_obj = CypherAuthentication.new(url, connection, params)
51
- auth_obj.authenticate
52
- response = connection.get(url)
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
41
+ # Opens a session to the database
42
+ # @see Neo4j::Session#open
43
+ #
44
+ # @param [String] endpoint_url - the url to the neo4j server, defaults to 'http://localhost:7474'
45
+ # @param [Hash] params faraday params, see #create_connection or an already created faraday connection
46
+ def self.open(endpoint_url = nil, params = {})
47
+ extract_basic_auth(endpoint_url, params)
48
+ connection = params[:connection] || create_connection(params)
49
+ url = endpoint_url || 'http://localhost:7474'
50
+ auth_obj = CypherAuthentication.new(url, connection, params)
51
+ auth_obj.authenticate
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, auth_obj)
55
+ end
56
56
 
57
- def self.establish_session(root_data, connection, auth_obj)
58
- data_url = root_data['data']
59
- data_url << '/' unless data_url.nil? || data_url.end_with?('/')
60
- CypherSession.new(data_url, connection, auth_obj)
61
- end
57
+ def self.establish_session(root_data, connection, auth_obj)
58
+ data_url = root_data['data']
59
+ data_url << '/' unless data_url.nil? || data_url.end_with?('/')
60
+ CypherSession.new(data_url, connection, auth_obj)
61
+ end
62
62
 
63
- def self.extract_basic_auth(url, params)
64
- return unless url && URI(url).userinfo
65
- params[:basic_auth] = {
66
- username: URI(url).user,
67
- password: URI(url).password
68
- }
69
- end
63
+ def self.extract_basic_auth(url, params)
64
+ return unless url && URI(url).userinfo
65
+ params[:basic_auth] = {
66
+ username: URI(url).user,
67
+ password: URI(url).password
68
+ }
69
+ end
70
70
 
71
- private_class_method :extract_basic_auth
71
+ private_class_method :extract_basic_auth
72
72
 
73
- def db_type
74
- :server_db
75
- end
73
+ def db_type
74
+ :server_db
75
+ end
76
76
 
77
- def to_s
78
- "#{self.class} url: '#{@resource_url}'"
79
- end
77
+ def to_s
78
+ "#{self.class} url: '#{@resource_url}'"
79
+ end
80
80
 
81
- def inspect
82
- "#{to_s} version: '#{version}'"
83
- end
81
+ def inspect
82
+ "#{self} version: '#{version}'"
83
+ end
84
84
 
85
- def version
86
- resource_data ? resource_data['neo4j_version'] : ''
87
- end
85
+ def version
86
+ resource_data ? resource_data['neo4j_version'] : ''
87
+ end
88
88
 
89
- def initialize_resource(data_url)
90
- response = @connection.get(data_url)
91
- expect_response_code(response,200)
92
- data_resource = response.body
93
- raise "No data_resource for #{response.body}" unless data_resource
94
- # store the resource data
95
- init_resource_data(data_resource, data_url)
96
- end
89
+ def initialize_resource(data_url)
90
+ response = @connection.get(data_url)
91
+ expect_response_code(response, 200)
92
+ data_resource = response.body
93
+ fail "No data_resource for #{response.body}" unless data_resource
94
+ # store the resource data
95
+ init_resource_data(data_resource, data_url)
96
+ end
97
97
 
98
- def close
99
- super
100
- Neo4j::Transaction.unregister_current
101
- end
98
+ def close
99
+ super
100
+ Neo4j::Transaction.unregister_current
101
+ end
102
102
 
103
- def begin_tx
104
- if Neo4j::Transaction.current
105
- # Handle nested transaction "placebo transaction"
106
- Neo4j::Transaction.current.push_nested!
107
- else
108
- wrap_resource(self, 'transaction', CypherTransaction, :post, @connection)
103
+ def begin_tx
104
+ if Neo4j::Transaction.current
105
+ # Handle nested transaction "placebo transaction"
106
+ Neo4j::Transaction.current.push_nested!
107
+ else
108
+ wrap_resource(@connection)
109
+ end
110
+ Neo4j::Transaction.current
109
111
  end
110
- Neo4j::Transaction.current
111
- end
112
112
 
113
- def create_node(props = nil, labels = [])
114
- CypherNode.new self, _query_or_fail(cypher_string(labels, props), true, cypher_prop_list(props))
115
- end
113
+ def create_node(props = nil, labels = [])
114
+ id = _query_or_fail(cypher_string(labels, props), true, cypher_prop_list(props))
115
+ value = props.nil? ? id : {'id' => id, 'metadata' => {'labels' => labels}, 'data' => props}
116
+ CypherNode.new(self, value)
117
+ end
116
118
 
117
- def load_node(neo_id)
118
- load_entity(CypherNode, _query("MATCH (n) WHERE ID(n) = #{neo_id} RETURN n"))
119
- end
119
+ def load_node(neo_id)
120
+ load_entity(CypherNode, _query("MATCH (n) WHERE ID(n) = #{neo_id} RETURN n"))
121
+ end
120
122
 
121
- def load_relationship(neo_id)
122
- load_entity(CypherRelationship, _query("MATCH (n)-[r]-() WHERE ID(r) = #{neo_id} RETURN r"))
123
- end
123
+ def load_relationship(neo_id)
124
+ load_entity(CypherRelationship, _query("MATCH (n)-[r]-() WHERE ID(r) = #{neo_id} RETURN r"))
125
+ end
124
126
 
125
- def load_entity(clazz, cypher_response)
126
- return nil if cypher_response.data.nil? || cypher_response.data[0].nil?
127
- data = if cypher_response.is_transaction_response?
128
- cypher_response.rest_data_with_id
129
- else
130
- cypher_response.first_data
131
- end
132
-
133
- if cypher_response.error?
134
- cypher_response.raise_error
135
- elsif cypher_response.error_msg =~ /not found/ # Ugly that the Neo4j API gives us this error message
136
- return nil
137
- else
138
- clazz.new(self, data)
127
+ def load_entity(clazz, cypher_response)
128
+ return nil if cypher_response.data.nil? || cypher_response.data[0].nil?
129
+ data = if cypher_response.transaction_response?
130
+ cypher_response.rest_data_with_id
131
+ else
132
+ cypher_response.first_data
133
+ end
134
+
135
+ if cypher_response.error?
136
+ cypher_response.raise_error
137
+ elsif cypher_response.error_msg =~ /not found/ # Ugly that the Neo4j API gives us this error message
138
+ return nil
139
+ else
140
+ clazz.new(self, data)
141
+ end
139
142
  end
140
- end
141
143
 
142
- def create_label(name)
143
- CypherLabel.new(self, name)
144
- end
144
+ def create_label(name)
145
+ CypherLabel.new(self, name)
146
+ end
145
147
 
146
- def uniqueness_constraints(label)
147
- schema_properties("#{@resource_url}schema/constraint/#{label}/uniqueness")
148
- end
148
+ def uniqueness_constraints(label)
149
+ schema_properties("#{@resource_url}schema/constraint/#{label}/uniqueness")
150
+ end
149
151
 
150
- def indexes(label)
151
- schema_properties("#{@resource_url}schema/index/#{label}")
152
- end
152
+ def indexes(label)
153
+ schema_properties("#{@resource_url}schema/index/#{label}")
154
+ end
153
155
 
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) } }
158
- end
156
+ def schema_properties(query_string)
157
+ response = @connection.get(query_string)
158
+ expect_response_code(response, 200)
159
+ {property_keys: response.body.map { |row| row['property_keys'].map(&:to_sym) }}
160
+ end
159
161
 
160
- def find_all_nodes(label_name)
161
- search_result_to_enumerable_first_column(_query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)"))
162
- end
162
+ def find_all_nodes(label_name)
163
+ search_result_to_enumerable_first_column(_query_or_fail("MATCH (n:`#{label_name}`) RETURN ID(n)"))
164
+ end
163
165
 
164
- def find_nodes(label_name, key, value)
165
- value = "'#{value}'" if value.is_a? String
166
+ def find_nodes(label_name, key, value)
167
+ value = "'#{value}'" if value.is_a? String
166
168
 
167
- response = _query_or_fail <<-CYPHER
168
- MATCH (n:`#{label_name}`)
169
- WHERE n.#{key} = #{value}
170
- RETURN ID(n)
171
- CYPHER
172
- search_result_to_enumerable_first_column(response)
173
- end
169
+ response = _query_or_fail <<-CYPHER
170
+ MATCH (n:`#{label_name}`)
171
+ WHERE n.#{key} = #{value}
172
+ RETURN ID(n)
173
+ CYPHER
174
+ search_result_to_enumerable_first_column(response)
175
+ end
174
176
 
175
- def query(*args)
176
- if [[String], [String, Hash]].include?(args.map(&:class))
177
- query, params = args[0,2]
178
- response = _query(query, params)
179
- response.raise_error if response.error?
180
- response.to_node_enumeration(query)
181
- else
182
- options = args[0] || {}
183
- Neo4j::Core::Query.new(options.merge(session: self))
177
+ def query(*args)
178
+ if [[String], [String, Hash]].include?(args.map(&:class))
179
+ query, params = args[0, 2]
180
+ response = _query(query, params)
181
+ response.raise_error if response.error?
182
+ response.to_node_enumeration(query)
183
+ else
184
+ options = args[0] || {}
185
+ Neo4j::Core::Query.new(options.merge(session: self))
186
+ end
184
187
  end
185
- end
186
188
 
187
- def _query_data(q)
188
- r = _query_or_fail(q, true)
189
- # the response is different if we have a transaction or not
190
- Neo4j::Transaction.current ? r : r['data']
191
- end
189
+ def _query_data(q)
190
+ r = _query_or_fail(q, true)
191
+ # the response is different if we have a transaction or not
192
+ Neo4j::Transaction.current ? r : r['data']
193
+ end
192
194
 
193
- def _query_or_fail(q, single_row = false, params=nil)
194
- response = _query(q, params)
195
- response.raise_error if response.error?
196
- single_row ? response.first_data : response
197
- end
195
+ def _query_or_fail(q, single_row = false, params = nil)
196
+ response = _query(q, params)
197
+ response.raise_error if response.error?
198
+ single_row ? response.first_data : response
199
+ end
198
200
 
199
- def _query_entity_data(q, id = nil, params = nil)
200
- response = _query(q, params)
201
- response.raise_error if response.error?
202
- response.entity_data(id)
203
- end
201
+ def _query_entity_data(q, id = nil, params = nil)
202
+ response = _query(q, params)
203
+ response.raise_error if response.error?
204
+ response.entity_data(id)
205
+ end
204
206
 
205
- def _query(q, params = nil)
206
- curr_tx = Neo4j::Transaction.current
207
- if (curr_tx)
208
- curr_tx._query(q, params)
209
- else
210
- url = resource_url('cypher')
211
- q = params.nil? ? { 'query' => q } : { 'query' => q, 'params' => params}
212
- response = @connection.post(url, q)
213
- CypherResponse.create_with_no_tx(response)
207
+ def _query(q, params = nil)
208
+ # puts "q #{q}"
209
+ curr_tx = Neo4j::Transaction.current
210
+ if curr_tx
211
+ curr_tx._query(q, params)
212
+ else
213
+ url = resource_url('cypher')
214
+ q = params.nil? ? {'query' => q} : {'query' => q, 'params' => params}
215
+ response = @connection.post(url, q)
216
+ CypherResponse.create_with_no_tx(response)
217
+ end
214
218
  end
215
- end
216
219
 
217
- def search_result_to_enumerable_first_column(response)
218
- return [] unless response.data
219
- if Neo4j::Transaction.current
220
- search_result_to_enumerable_first_column_with_tx(response)
221
- else
222
- search_result_to_enumerable_first_column_without_tx(response)
220
+ def search_result_to_enumerable_first_column(response)
221
+ return [] unless response.data
222
+ if Neo4j::Transaction.current
223
+ search_result_to_enumerable_first_column_with_tx(response)
224
+ else
225
+ search_result_to_enumerable_first_column_without_tx(response)
226
+ end
223
227
  end
224
- end
225
228
 
226
- def search_result_to_enumerable_first_column_with_tx(response)
227
- Enumerator.new do |yielder|
228
- response.data.each do |data|
229
- data["row"].each do |id|
230
- yielder << CypherNode.new(self, id).wrapper
229
+ def search_result_to_enumerable_first_column_with_tx(response)
230
+ Enumerator.new do |yielder|
231
+ response.data.each do |data|
232
+ data['row'].each do |id|
233
+ yielder << CypherNode.new(self, id).wrapper
234
+ end
231
235
  end
232
236
  end
233
237
  end
234
- end
235
238
 
236
- def search_result_to_enumerable_first_column_without_tx(response)
237
- Enumerator.new do |yielder|
238
- response.data.each do |data|
239
- yielder << CypherNode.new(self, data[0]).wrapper
239
+ def search_result_to_enumerable_first_column_without_tx(response)
240
+ Enumerator.new do |yielder|
241
+ response.data.each do |data|
242
+ yielder << CypherNode.new(self, data[0]).wrapper
243
+ end
240
244
  end
241
245
  end
242
- end
243
246
 
244
- def map_column(key, map, 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
247
+ def map_column(key, map, data)
248
+ if map[key] == :node
249
+ CypherNode.new(self, data).wrapper
250
+ elsif map[key] == :rel || map[:key] || :relationship
251
+ CypherRelationship.new(self, data)
252
+ else
253
+ data
254
+ end
251
255
  end
252
256
  end
253
257
  end