neo4j-core 3.1.1 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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