neo4j-core 5.1.14 → 6.0.0.alpha.1

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