neo4j-core 5.1.14 → 6.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/neo4j-core.rb +1 -1
  3. data/lib/neo4j-core/helpers.rb +6 -0
  4. data/lib/neo4j-core/query.rb +88 -40
  5. data/lib/neo4j-core/query_clauses.rb +67 -67
  6. data/lib/neo4j-core/version.rb +1 -1
  7. data/lib/neo4j-embedded/embedded_label.rb +16 -14
  8. data/lib/neo4j-embedded/embedded_node.rb +115 -113
  9. data/lib/neo4j-embedded/embedded_relationship.rb +53 -51
  10. data/lib/neo4j-embedded/embedded_session.rb +5 -14
  11. data/lib/neo4j-embedded/label.rb +2 -1
  12. data/lib/neo4j-server/cypher_label.rb +8 -7
  13. data/lib/neo4j-server/cypher_relationship.rb +1 -1
  14. data/lib/neo4j-server/cypher_response.rb +3 -2
  15. data/lib/neo4j-server/cypher_transaction.rb +1 -6
  16. data/lib/neo4j-server/resource.rb +1 -1
  17. data/lib/neo4j/core/cypher_session.rb +28 -0
  18. data/lib/neo4j/core/cypher_session/adaptors.rb +108 -0
  19. data/lib/neo4j/core/cypher_session/adaptors/embedded.rb +81 -0
  20. data/lib/neo4j/core/cypher_session/adaptors/http.rb +159 -0
  21. data/lib/neo4j/core/cypher_session/responses.rb +27 -0
  22. data/lib/neo4j/core/cypher_session/responses/embedded.rb +77 -0
  23. data/lib/neo4j/core/cypher_session/responses/http.rb +104 -0
  24. data/lib/neo4j/core/cypher_session/result.rb +39 -0
  25. data/lib/neo4j/core/instrumentable.rb +36 -0
  26. data/lib/neo4j/core/node.rb +28 -0
  27. data/lib/neo4j/core/path.rb +15 -0
  28. data/lib/neo4j/core/relationship.rb +25 -0
  29. data/lib/neo4j/core/wrappable.rb +35 -0
  30. data/lib/neo4j/label.rb +7 -0
  31. data/lib/neo4j/session.rb +3 -3
  32. data/lib/neo4j/transaction.rb +1 -24
  33. data/neo4j-core.gemspec +2 -2
  34. metadata +22 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a86ca1a3a458ea6ecb32b39dc5e3b3bf1dd4a0b0
4
- data.tar.gz: 69150678225a39745ade9246252a02e39e7e1192
3
+ metadata.gz: d2e549ac9b629bd47019215c2457d66c6b355a2f
4
+ data.tar.gz: 717fb2cc5363c0a7a9726ae4d686e504634d7310
5
5
  SHA512:
6
- metadata.gz: a250f017521e2ccdccc62eca1735eba6a46ac4f75194718129274c91ab2dfecd280c5cd3610382af8ca3e733459816158dd5e395742d87f691afe0c568255fd0
7
- data.tar.gz: 569162a558aaa56a76cb922287e5be484238f0f6c94524331ef1a3852117bf45b125edbc07115ec10d43af69af40e411255c42e90f4ce51edd12f18e77a6a9cb
6
+ metadata.gz: 14df3ab1fb20692a66036201039f66861b38fc340b3c63c7051d977b2a718c09a9daa3b5d717920ddaa5228089c899f8cf9f611c2e11e6cda992af6fc6d1838a
7
+ data.tar.gz: ece61afe7b0c8c21db72322bfe5143ccc9ab7ef84dc6b01f7b7416b7978b28a082b0edb7dbc5587ed390cc9aa2da3555f4aad1fa11e96fb28e76e5de9d90e7c4
data/lib/neo4j-core.rb CHANGED
@@ -26,7 +26,7 @@ require 'neo4j-server'
26
26
  require 'rake'
27
27
  require 'neo4j/rake_tasks'
28
28
 
29
- if RUBY_PLATFORM == 'java'
29
+ if RUBY_PLATFORM == 'java' && !ENV['WITHOUT_NEO4J_EMBEDDED']
30
30
  require 'neo4j-embedded'
31
31
  else
32
32
  # just for the tests
@@ -13,5 +13,11 @@ module Neo4j
13
13
  end
14
14
  end
15
15
  end
16
+
17
+ module Config
18
+ def self.using_new_session?
19
+ ENV.key?('NEW_NEO4J_SESSIONS')
20
+ end
21
+ end
16
22
  end
17
23
  end
@@ -18,16 +18,61 @@ module Neo4j
18
18
 
19
19
  attr_accessor :clauses
20
20
 
21
+ class Parameters
22
+ def initialize(hash = nil)
23
+ @parameters = (hash || {})
24
+ end
25
+
26
+ def to_hash
27
+ @parameters
28
+ end
29
+
30
+ def copy
31
+ self.class.new(@parameters.dup)
32
+ end
33
+
34
+ def add_param(key, value)
35
+ free_param_key(key).tap do |k|
36
+ @parameters[k.freeze] = value
37
+ end
38
+ end
39
+
40
+ def remove_param(key)
41
+ @parameters.delete(key.to_sym)
42
+ end
43
+
44
+ def add_params(params)
45
+ params.map do |key, value|
46
+ add_param(key, value)
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def free_param_key(key)
53
+ k = key.to_sym
54
+
55
+ return k if !@parameters.key?(k)
56
+
57
+ i = 2
58
+ i += 1 while @parameters.key?("#{key}#{i}".to_sym)
59
+
60
+ "#{key}#{i}".to_sym
61
+ end
62
+ end
63
+
21
64
  class << self
22
65
  attr_accessor :pretty_cypher
23
66
  end
24
67
 
25
68
  def initialize(options = {})
26
- @session = options[:session] || Neo4j::Session.current
69
+ @session = options[:session]
70
+ @session = Neo4j::Session.current if !options.key?(:session)
27
71
 
28
72
  @options = options
29
73
  @clauses = []
30
74
  @_params = {}
75
+ @params = Parameters.new
31
76
  end
32
77
 
33
78
  def inspect
@@ -113,9 +158,7 @@ module Neo4j
113
158
  METHODS = %w(start match optional_match using where create create_unique merge set on_create_set on_match_set remove unwind delete with return order skip limit)
114
159
  BREAK_METHODS = %(with)
115
160
 
116
- CLAUSIFY_CLAUSE = proc do |method|
117
- const_get(method.to_s.split('_').map(&:capitalize).join + 'Clause')
118
- end
161
+ CLAUSIFY_CLAUSE = proc { |method| const_get(method.to_s.split('_').map(&:capitalize).join + 'Clause') }
119
162
 
120
163
  CLAUSES = METHODS.map(&CLAUSIFY_CLAUSE)
121
164
 
@@ -171,9 +214,7 @@ module Neo4j
171
214
  # Query.new.match('(q: Person {id: {id}})').params(id: 12)
172
215
  #
173
216
  def params(args)
174
- @_params = @_params.merge(args)
175
-
176
- self
217
+ copy.tap { |new_query| new_query.instance_variable_get('@params').add_params(args) }
177
218
  end
178
219
 
179
220
  def unwrapped
@@ -187,25 +228,19 @@ module Neo4j
187
228
 
188
229
  def response
189
230
  return @response if @response
231
+
190
232
  cypher = to_cypher
191
233
  pretty_cypher = to_cypher(pretty: true) if self.class.pretty_cypher
192
234
 
193
235
  @response = @session._query(cypher, merge_params, context: @options[:context], pretty_cypher: pretty_cypher)
194
236
 
195
- if !response.respond_to?(:error?) || !response.error?
196
- response
197
- else
198
- response.raise_cypher_error
199
- end
237
+ (!response.respond_to?(:error?) || !response.error?) ? response : response.raise_cypher_error
200
238
  end
201
239
 
202
240
  def match_nodes(hash, optional_match = false)
203
241
  hash.inject(self) do |query, (variable, node_object)|
204
- neo_id = if node_object.respond_to?(:neo_id)
205
- node_object.neo_id
206
- else
207
- node_object
208
- end
242
+ neo_id = (node_object.respond_to?(:neo_id) ? node_object.neo_id : node_object)
243
+
209
244
  match_method = optional_match ? :optional_match : :match
210
245
  query.send(match_method, variable).where(variable => {neo_id: neo_id})
211
246
  end
@@ -267,11 +302,7 @@ module Neo4j
267
302
  column = columns[0]
268
303
  query.map { |row| row[column] }
269
304
  else
270
- query.map do |row|
271
- columns.map do |column|
272
- row[column]
273
- end
274
- end
305
+ query.map { |row| columns.map { |column| row[column] } }
275
306
  end
276
307
  end
277
308
 
@@ -290,20 +321,39 @@ module Neo4j
290
321
  EMPTY = ' '
291
322
  NEWLINE = "\n"
292
323
  def to_cypher(options = {})
293
- cypher_string = PartitionedClauses.new(@clauses).map do |clauses|
324
+ join_string = options[:pretty] ? NEWLINE : EMPTY
325
+
326
+ cypher_string = partitioned_clauses.map do |clauses|
294
327
  clauses_by_class = clauses.group_by(&:class)
295
328
 
296
329
  cypher_parts = CLAUSES.map do |clause_class|
297
- clause_class.to_cypher(clauses, options) if clauses = clauses_by_class[clause_class]
298
- end
330
+ clause_class.to_cypher(clauses, options[:pretty]) if clauses = clauses_by_class[clause_class]
331
+ end.compact
299
332
 
300
- cypher_parts.compact!
301
- cypher_parts.join(options[:pretty] ? NEWLINE : EMPTY).tap(&:strip!)
302
- end.join(options[:pretty] ? NEWLINE : EMPTY)
333
+ cypher_parts.join(join_string).tap(&:strip!)
334
+ end.join(join_string)
303
335
 
304
336
  cypher_string = "CYPHER #{@options[:parser]} #{cypher_string}" if @options[:parser]
305
337
  cypher_string.tap(&:strip!)
306
338
  end
339
+ alias_method :cypher, :to_cypher
340
+
341
+ def pretty_cypher
342
+ to_cypher(pretty: true)
343
+ end
344
+
345
+ def context
346
+ @options[:context]
347
+ end
348
+
349
+ def parameters
350
+ to_cypher
351
+ merge_params
352
+ end
353
+
354
+ def partitioned_clauses
355
+ @partitioned_clauses ||= PartitionedClauses.new(@clauses)
356
+ end
307
357
 
308
358
  def print_cypher
309
359
  puts to_cypher(pretty: true).gsub(/\e[^m]+m/, '')
@@ -332,20 +382,18 @@ module Neo4j
332
382
  end.params(other._params)
333
383
  end
334
384
 
335
- MEMOIZED_INSTANCE_VARIABLES = [:response, :merge_params]
336
385
  def copy
337
386
  dup.tap do |query|
338
- MEMOIZED_INSTANCE_VARIABLES.each do |var|
339
- query.instance_variable_set("@#{var}", nil)
340
- end
387
+ to_cypher
388
+ query.instance_variable_set('@params', @params.copy)
389
+ query.instance_variable_set('@partitioned_clauses', nil)
390
+ query.instance_variable_set('@response', nil)
341
391
  end
342
392
  end
343
393
 
344
394
  def clause?(method)
345
395
  clause_class = DEFINED_CLAUSES[method] || CLAUSIFY_CLAUSE.call(method)
346
- clauses.any? do |clause|
347
- clause.is_a?(clause_class)
348
- end
396
+ clauses.any? { |clause| clause.is_a?(clause_class) }
349
397
  end
350
398
 
351
399
  protected
@@ -357,9 +405,7 @@ module Neo4j
357
405
  end
358
406
 
359
407
  def remove_clause_class(clause_class)
360
- @clauses = @clauses.reject do |clause|
361
- clause.is_a?(clause_class)
362
- end
408
+ @clauses = @clauses.reject { |clause| clause.is_a?(clause_class) }
363
409
  end
364
410
 
365
411
  private
@@ -367,7 +413,7 @@ module Neo4j
367
413
  def build_deeper_query(clause_class, args = {}, options = {})
368
414
  copy.tap do |new_query|
369
415
  new_query.add_clauses [nil] if [nil, WithClause].include?(clause_class)
370
- new_query.add_clauses clause_class.from_args(args, options) if clause_class
416
+ new_query.add_clauses clause_class.from_args(args, new_query.instance_variable_get('@params'), options) if clause_class
371
417
  end
372
418
  end
373
419
 
@@ -430,9 +476,11 @@ module Neo4j
430
476
  end
431
477
  end
432
478
 
479
+ # SHOULD BE DEPRECATED
433
480
  def merge_params
434
481
  @clauses.compact!
435
- @merge_params ||= @clauses.inject(@_params) { |params, clause| params.merge!(clause.params) }
482
+ @merge_params ||= @clauses.inject(@params.to_hash) { |params, clause| params.merge!(clause.params) }
483
+ @params.to_hash
436
484
  end
437
485
  end
438
486
  end
@@ -9,25 +9,27 @@ module Neo4j
9
9
  end
10
10
  end
11
11
 
12
-
13
12
  class Clause
14
13
  UNDERSCORE = '_'
15
14
  COMMA_SPACE = ', '
16
15
  AND = ' AND '
17
16
 
18
17
  attr_accessor :params, :arg
19
- attr_reader :options
18
+ attr_reader :options, :param_vars_added
20
19
 
21
- def initialize(arg, options = {})
20
+ def initialize(arg, params, options = {})
22
21
  @arg = arg
23
22
  @options = options
24
- @params = {}
23
+ @params = params
24
+ @param_vars_added = []
25
25
  end
26
26
 
27
27
  def value
28
+ return @value if @value
29
+
28
30
  [String, Symbol, Integer, Hash, NilClass].each do |arg_class|
29
31
  from_method = "from_#{arg_class.name.downcase}"
30
- return send(from_method, @arg) if @arg.is_a?(arg_class) && self.respond_to?(from_method)
32
+ return @value = send(from_method, @arg) if @arg.is_a?(arg_class) && self.respond_to?(from_method)
31
33
  end
32
34
 
33
35
  fail ArgError
@@ -124,21 +126,19 @@ module Neo4j
124
126
  keyword.downcase
125
127
  end
126
128
 
127
- def from_args(args, options = {})
129
+ def from_args(args, params, options = {})
128
130
  args.flatten!
129
- args.map { |arg| from_arg(arg, options) }.tap(&:compact!)
131
+ args.map { |arg| from_arg(arg, params, options) }.tap(&:compact!)
130
132
  end
131
133
 
132
- def from_arg(arg, options = {})
133
- new(arg, options) if !arg.respond_to?(:empty?) || !arg.empty?
134
+ def from_arg(arg, params, options = {})
135
+ new(arg, params, options) if !arg.respond_to?(:empty?) || !arg.empty?
134
136
  end
135
137
 
136
- def to_cypher(clauses, options = {})
137
- @question_mark_param_index = 1
138
-
139
- string = clause_string(clauses, options)
138
+ def to_cypher(clauses, pretty = false)
139
+ string = clause_string(clauses, pretty)
140
140
 
141
- final_keyword = if options[:pretty]
141
+ final_keyword = if pretty
142
142
  "#{clause_color}#{keyword}#{ANSI::CLEAR}"
143
143
  else
144
144
  keyword
@@ -147,11 +147,11 @@ module Neo4j
147
147
  "#{final_keyword} #{string}" if string.size > 0
148
148
  end
149
149
 
150
- def clause_string(clauses, options = {})
151
- join_string = clause_join + (options[:pretty] ? "\n " : '')
150
+ def clause_string(clauses, pretty)
151
+ join_string = clause_join + (pretty ? "\n " : '')
152
152
 
153
153
  strings = clause_strings(clauses)
154
- string = ((options[:pretty] && strings.size > 1) ? "\n " : '')
154
+ string = ((pretty && strings.size > 1) ? "\n " : '')
155
155
  string + strings.join(join_string).strip
156
156
  end
157
157
 
@@ -169,6 +169,16 @@ module Neo4j
169
169
  key.gsub!(/^_+|_+$/, '')
170
170
  end
171
171
 
172
+ def add_param(key, value)
173
+ @param_vars_added << key
174
+ @params.add_param(key, value)
175
+ end
176
+
177
+ def add_params(keys_and_values)
178
+ @param_vars_added += keys_and_values.keys
179
+ @params.add_params(keys_and_values)
180
+ end
181
+
172
182
  private
173
183
 
174
184
  def key_value_string(key, value, previous_keys = [], is_set = false)
@@ -176,14 +186,14 @@ module Neo4j
176
186
  self.class.paramaterize_key!(param)
177
187
 
178
188
  if value.is_a?(Range)
179
- add_params("#{param}_range_min" => value.min, "#{param}_range_max" => value.max)
189
+ min_param, max_param = add_params("#{param}_range_min" => value.min, "#{param}_range_max" => value.max)
180
190
 
181
- "#{key} IN RANGE({#{param}_range_min}, {#{param}_range_max})"
191
+ "#{key} IN RANGE({#{min_param}}, {#{max_param}})"
182
192
  else
183
193
  value = value.first if array_value?(value, is_set) && value.size == 1
184
194
  operator = array_value?(value, is_set) ? 'IN' : '='
185
195
 
186
- add_param(param, value)
196
+ param = add_param(param, value)
187
197
 
188
198
  "#{key} #{operator} {#{param}}"
189
199
  end
@@ -193,16 +203,6 @@ module Neo4j
193
203
  value.is_a?(Array) && !is_set
194
204
  end
195
205
 
196
- def add_param(key, value)
197
- @params[key.freeze.to_sym] = value
198
- end
199
-
200
- def add_params(params)
201
- params.each do |key, value|
202
- add_param(key, value)
203
- end
204
- end
205
-
206
206
  def format_label(label_arg)
207
207
  if label_arg.is_a?(Array)
208
208
  return label_arg.map { |arg| format_label(arg) }.join
@@ -225,7 +225,7 @@ module Neo4j
225
225
  "#{key}: #{value}"
226
226
  else
227
227
  param_key = "#{prefix}#{key}".gsub('::', '_')
228
- add_param(param_key, value)
228
+ param_key = add_param(param_key, value)
229
229
  "#{key}: {#{param_key}}"
230
230
  end
231
231
  end.join(Clause::COMMA_SPACE)
@@ -310,7 +310,7 @@ module Neo4j
310
310
  param = [previous_keys + [key]].join(UNDERSCORE)
311
311
  self.class.paramaterize_key!(param)
312
312
 
313
- add_params(param => pattern)
313
+ param = add_param(param, pattern)
314
314
 
315
315
  "#{key} =~ {#{param}}"
316
316
  end
@@ -318,36 +318,22 @@ module Neo4j
318
318
  class << self
319
319
  ARG_HAS_QUESTION_MARK_REGEX = /(^|\(|\s)\?(\s|\)|$)/
320
320
 
321
- def from_args(args, options = {})
322
- query_string, params = args
323
-
324
- if query_string.is_a?(String) && (query_string.match(ARG_HAS_QUESTION_MARK_REGEX) || params.is_a?(Hash))
325
- if !params.is_a?(Hash)
326
- question_mark_params_param = self.question_mark_params_param
327
- query_string = query_string.gsub(ARG_HAS_QUESTION_MARK_REGEX, "\\1{#{question_mark_params_param}}\\2")
328
- params = {question_mark_params_param.to_sym => params}
329
- end
321
+ def from_args(args, params, options = {})
322
+ query_string, params_arg = args
330
323
 
331
- clause = from_arg(query_string, options).tap do |clause|
332
- clause.params.merge!(params)
324
+ if query_string.is_a?(String) && (query_string.match(ARG_HAS_QUESTION_MARK_REGEX) || params_arg.is_a?(Hash))
325
+ if params_arg.is_a?(Hash)
326
+ params.add_params(params_arg)
327
+ else
328
+ param_var = params.add_params(question_mark_param: params_arg)[0]
329
+ query_string = query_string.gsub(ARG_HAS_QUESTION_MARK_REGEX, "\\1{#{param_var}}\\2")
333
330
  end
334
331
 
335
- [clause]
332
+ [from_arg(query_string, params, options)]
336
333
  else
337
334
  super
338
335
  end
339
336
  end
340
-
341
- def question_mark_params_param
342
- "question_mark_param#{question_mark_param_index}"
343
- end
344
-
345
- def question_mark_param_index
346
- @question_mark_param_index ||= 1
347
- @question_mark_param_index.tap do
348
- @question_mark_param_index += 1
349
- end
350
- end
351
337
  end
352
338
  end
353
339
 
@@ -464,6 +450,10 @@ module Neo4j
464
450
  def clause_color
465
451
  ANSI::MAGENTA
466
452
  end
453
+
454
+ def clause_join
455
+ ' MERGE '
456
+ end
467
457
  end
468
458
  end
469
459
 
@@ -524,15 +514,13 @@ module Neo4j
524
514
  KEYWORD = 'LIMIT'
525
515
 
526
516
  def from_string(value)
527
- clause_id = "#{self.class.keyword_downcase}_#{value}"
528
- add_param(clause_id, value.to_i)
529
- "{#{clause_id}}"
517
+ param_var = "#{self.class.keyword_downcase}_#{value}"
518
+ param_var = add_param(param_var, value.to_i)
519
+ "{#{param_var}}"
530
520
  end
531
521
 
532
522
  def from_integer(value)
533
- clause_id = "#{self.class.keyword_downcase}_#{value}"
534
- add_param(clause_id, value)
535
- "{#{clause_id}}"
523
+ from_string(value)
536
524
  end
537
525
 
538
526
  def from_nilclass(value)
@@ -541,7 +529,13 @@ module Neo4j
541
529
 
542
530
  class << self
543
531
  def clause_strings(clauses)
544
- [clauses.last.value]
532
+ result_clause = clauses.last
533
+
534
+ clauses[0..-2].map(&:param_vars_added).flatten.grep(/^limit_\d+$/).each do |var|
535
+ result_clause.params.remove_param(var)
536
+ end
537
+
538
+ [result_clause.value]
545
539
  end
546
540
  end
547
541
  end
@@ -551,19 +545,25 @@ module Neo4j
551
545
 
552
546
  def from_string(value)
553
547
  clause_id = "#{self.class.keyword_downcase}_#{value}"
554
- add_param(clause_id, value.to_i)
548
+ clause_id = add_param(clause_id, value.to_i)
555
549
  "{#{clause_id}}"
556
550
  end
557
551
 
558
552
  def from_integer(value)
559
553
  clause_id = "#{self.class.keyword_downcase}_#{value}"
560
- add_param(clause_id, value)
554
+ clause_id = add_param(clause_id, value)
561
555
  "{#{clause_id}}"
562
556
  end
563
557
 
564
558
  class << self
565
559
  def clause_strings(clauses)
566
- [clauses.last.value]
560
+ result_clause = clauses.last
561
+
562
+ clauses[0..-2].map(&:param_vars_added).flatten.grep(/^skip_\d+$/).each do |var|
563
+ result_clause.params.remove_param(var)
564
+ end
565
+
566
+ [result_clause.value]
567
567
  end
568
568
  end
569
569
  end
@@ -576,8 +576,8 @@ module Neo4j
576
576
  when String, Symbol then "#{key}:`#{value}`"
577
577
  when Hash
578
578
  if @options[:set_props]
579
- add_param("#{key}_set_props", value)
580
- "#{key} = {#{key}_set_props}"
579
+ param = add_param("#{key}_set_props", value)
580
+ "#{key} = {#{param}}"
581
581
  else
582
582
  value.map { |k, v| key_value_string("#{key}.`#{k}`", v, ['setter'], true) }
583
583
  end