neo4j-core 4.0.7 → 5.0.0.rc.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.
- checksums.yaml +4 -4
- data/lib/ext/kernel.rb +9 -0
- data/lib/neo4j/label.rb +2 -1
- data/lib/neo4j/node.rb +8 -11
- data/lib/neo4j/property_container.rb +2 -7
- data/lib/neo4j/property_validator.rb +1 -1
- data/lib/neo4j/session.rb +24 -11
- data/lib/neo4j/tasks/config_server.rb +4 -1
- data/lib/neo4j/tasks/neo4j_server.rake +86 -109
- data/lib/neo4j/transaction.rb +17 -16
- data/lib/neo4j-core/cypher_translator.rb +1 -1
- data/lib/neo4j-core/query.rb +103 -47
- data/lib/neo4j-core/query_clauses.rb +177 -109
- data/lib/neo4j-core/query_find_in_batches.rb +19 -11
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-core.rb +3 -0
- data/lib/neo4j-embedded/cypher_response.rb +20 -5
- data/lib/neo4j-embedded/embedded_node.rb +26 -28
- data/lib/neo4j-embedded/embedded_session.rb +7 -6
- data/lib/neo4j-embedded/embedded_transaction.rb +2 -2
- data/lib/neo4j-embedded/label.rb +65 -0
- data/lib/neo4j-embedded/property.rb +5 -5
- data/lib/neo4j-embedded/to_java.rb +7 -13
- data/lib/neo4j-embedded.rb +1 -0
- data/lib/neo4j-server/cypher_node.rb +57 -67
- data/lib/neo4j-server/cypher_node_uncommited.rb +1 -1
- data/lib/neo4j-server/cypher_relationship.rb +10 -6
- data/lib/neo4j-server/cypher_response.rb +87 -51
- data/lib/neo4j-server/cypher_session.rb +80 -93
- data/lib/neo4j-server/cypher_transaction.rb +42 -33
- data/lib/neo4j-server/label.rb +40 -0
- data/lib/neo4j-server/resource.rb +11 -12
- data/lib/neo4j-server.rb +2 -0
- data/neo4j-core.gemspec +4 -1
- metadata +50 -6
- data/lib/neo4j-core/graph_json.rb +0 -35
data/lib/neo4j-core/query.rb
CHANGED
@@ -14,6 +14,9 @@ module Neo4j
|
|
14
14
|
class Query
|
15
15
|
include Neo4j::Core::QueryClauses
|
16
16
|
include Neo4j::Core::QueryFindInBatches
|
17
|
+
DEFINED_CLAUSES = {}
|
18
|
+
|
19
|
+
attr_accessor :clauses
|
17
20
|
|
18
21
|
def initialize(options = {})
|
19
22
|
@session = options[:session] || Neo4j::Session.current
|
@@ -99,17 +102,24 @@ module Neo4j
|
|
99
102
|
# DELETE clause
|
100
103
|
# @return [Query]
|
101
104
|
|
102
|
-
METHODS = %w(
|
105
|
+
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)
|
106
|
+
BREAK_METHODS = %(with)
|
107
|
+
|
108
|
+
CLAUSIFY_CLAUSE = proc do |method|
|
109
|
+
const_get(method.to_s.split('_').map(&:capitalize).join + 'Clause')
|
110
|
+
end
|
103
111
|
|
104
|
-
CLAUSES = METHODS.map
|
112
|
+
CLAUSES = METHODS.map(&CLAUSIFY_CLAUSE)
|
105
113
|
|
106
114
|
METHODS.each_with_index do |clause, i|
|
107
115
|
clause_class = CLAUSES[i]
|
108
116
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
117
|
+
DEFINED_CLAUSES[clause.to_sym] = clause_class
|
118
|
+
define_method(clause) do |*args|
|
119
|
+
build_deeper_query(clause_class, args).ergo do |result|
|
120
|
+
BREAK_METHODS.include?(clause) ? result.break : result
|
121
|
+
end
|
122
|
+
end
|
113
123
|
end
|
114
124
|
|
115
125
|
alias_method :offset, :skip
|
@@ -152,6 +162,15 @@ module Neo4j
|
|
152
162
|
self
|
153
163
|
end
|
154
164
|
|
165
|
+
def unwrapped
|
166
|
+
@_unwrapped_obj = true
|
167
|
+
self
|
168
|
+
end
|
169
|
+
|
170
|
+
def unwrapped?
|
171
|
+
!!@_unwrapped_obj
|
172
|
+
end
|
173
|
+
|
155
174
|
def response
|
156
175
|
return @response if @response
|
157
176
|
cypher = to_cypher
|
@@ -167,12 +186,18 @@ module Neo4j
|
|
167
186
|
|
168
187
|
include Enumerable
|
169
188
|
|
189
|
+
def count(var = nil)
|
190
|
+
v = var.nil? ? '*' : var
|
191
|
+
pluck("count(#{v})").first
|
192
|
+
end
|
193
|
+
|
170
194
|
def each
|
171
195
|
response = self.response
|
172
196
|
if response.is_a?(Neo4j::Server::CypherResponse)
|
197
|
+
response.unwrapped! if unwrapped?
|
173
198
|
response.to_node_enumeration
|
174
199
|
else
|
175
|
-
Neo4j::Embedded::ResultWrapper.new(response, to_cypher)
|
200
|
+
Neo4j::Embedded::ResultWrapper.new(response, to_cypher, unwrapped?)
|
176
201
|
end.each { |object| yield object }
|
177
202
|
end
|
178
203
|
|
@@ -201,12 +226,12 @@ module Neo4j
|
|
201
226
|
# Query.new.match(n: :Person).return(p: :name}.pluck('p, DISTINCT p.name') # => Array of [node, name] pairs
|
202
227
|
#
|
203
228
|
def pluck(*columns)
|
229
|
+
fail ArgumentError, 'No columns specified for Query#pluck' if columns.size.zero?
|
230
|
+
|
204
231
|
query = return_query(columns)
|
205
232
|
columns = query.response.columns
|
206
233
|
|
207
234
|
case columns.size
|
208
|
-
when 0
|
209
|
-
fail ArgumentError, 'No columns specified for Query#pluck'
|
210
235
|
when 1
|
211
236
|
column = columns[0]
|
212
237
|
query.map { |row| row[column] }
|
@@ -223,15 +248,7 @@ module Neo4j
|
|
223
248
|
query = copy
|
224
249
|
query.remove_clause_class(ReturnClause)
|
225
250
|
|
226
|
-
columns
|
227
|
-
if column_definition.is_a?(Hash)
|
228
|
-
column_definition.map { |k, v| "#{k}.#{v}" }
|
229
|
-
else
|
230
|
-
column_definition
|
231
|
-
end
|
232
|
-
end.flatten.map(&:to_sym)
|
233
|
-
|
234
|
-
query.return(columns)
|
251
|
+
query.return(*columns)
|
235
252
|
end
|
236
253
|
|
237
254
|
# Returns a CYPHER query string from the object query representation
|
@@ -239,22 +256,21 @@ module Neo4j
|
|
239
256
|
# Query.new.match(p: :Person).where(p: {age: 30}) # => "MATCH (p:Person) WHERE p.age = 30
|
240
257
|
#
|
241
258
|
# @return [String] Resulting cypher query string
|
259
|
+
EMPTY = ' '
|
242
260
|
def to_cypher
|
243
|
-
cypher_string =
|
261
|
+
cypher_string = PartitionedClauses.new(@clauses).map do |clauses|
|
244
262
|
clauses_by_class = clauses.group_by(&:class)
|
245
263
|
|
246
264
|
cypher_parts = CLAUSES.map do |clause_class|
|
247
|
-
clauses = clauses_by_class[clause_class]
|
248
|
-
|
249
|
-
clause_class.to_cypher(clauses) if clauses
|
265
|
+
clause_class.to_cypher(clauses) if clauses = clauses_by_class[clause_class]
|
250
266
|
end
|
251
267
|
|
252
|
-
|
253
|
-
|
254
|
-
end.join
|
268
|
+
cypher_parts.compact!
|
269
|
+
cypher_parts.join(EMPTY).tap(&:strip!)
|
270
|
+
end.join EMPTY
|
255
271
|
|
256
272
|
cypher_string = "CYPHER #{@options[:parser]} #{cypher_string}" if @options[:parser]
|
257
|
-
cypher_string.strip
|
273
|
+
cypher_string.tap(&:strip!)
|
258
274
|
end
|
259
275
|
|
260
276
|
# Returns a CYPHER query specifying the union of the callee object's query and the argument's query
|
@@ -289,9 +305,16 @@ module Neo4j
|
|
289
305
|
end
|
290
306
|
end
|
291
307
|
|
308
|
+
def clause?(method)
|
309
|
+
clause_class = DEFINED_CLAUSES[method] || CLAUSIFY_CLAUSE.call(method)
|
310
|
+
clauses.any? do |clause|
|
311
|
+
clause.is_a?(clause_class)
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
292
315
|
protected
|
293
316
|
|
294
|
-
attr_accessor :session, :options, :
|
317
|
+
attr_accessor :session, :options, :_params
|
295
318
|
|
296
319
|
def add_clauses(clauses)
|
297
320
|
@clauses += clauses
|
@@ -312,35 +335,68 @@ module Neo4j
|
|
312
335
|
end
|
313
336
|
end
|
314
337
|
|
315
|
-
|
316
|
-
|
317
|
-
|
338
|
+
class PartitionedClauses
|
339
|
+
def initialize(clauses)
|
340
|
+
@clauses = clauses
|
341
|
+
@partitioning = [[]]
|
318
342
|
end
|
319
|
-
end
|
320
343
|
|
321
|
-
|
322
|
-
|
344
|
+
include Enumerable
|
345
|
+
|
346
|
+
def each
|
347
|
+
generate_partitioning!
|
348
|
+
|
349
|
+
@partitioning.each { |partition| yield partition }
|
350
|
+
end
|
323
351
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
352
|
+
def generate_partitioning!
|
353
|
+
@partitioning = [[]]
|
354
|
+
|
355
|
+
@clauses.each do |clause|
|
356
|
+
if clause.nil? && !fresh_partition?
|
357
|
+
@partitioning << []
|
358
|
+
elsif clause_is_order_or_limit_directly_following_with_or_order?(clause)
|
359
|
+
second_to_last << clause
|
360
|
+
elsif clause_is_with_following_order_or_limit?(clause)
|
361
|
+
second_to_last << clause
|
362
|
+
second_to_last.sort_by! { |c| c.is_a?(::Neo4j::Core::QueryClauses::OrderClause) ? 1 : 0 }
|
363
|
+
else
|
364
|
+
@partitioning.last << clause
|
365
|
+
end
|
329
366
|
end
|
330
367
|
end
|
331
368
|
|
332
|
-
|
333
|
-
end
|
369
|
+
private
|
334
370
|
|
335
|
-
|
336
|
-
|
337
|
-
|
371
|
+
def fresh_partition?
|
372
|
+
@partitioning.last == []
|
373
|
+
end
|
338
374
|
|
339
|
-
|
340
|
-
|
341
|
-
params.each do |key, value|
|
342
|
-
params[key] = value.to_s if not passthrough_classes.any? { |klass| value.is_a?(klass) }
|
375
|
+
def second_to_last
|
376
|
+
@partitioning[-2]
|
343
377
|
end
|
378
|
+
|
379
|
+
def clause_is_order_or_limit_directly_following_with_or_order?(clause)
|
380
|
+
self.class.clause_is_order_or_limit?(clause) &&
|
381
|
+
@partitioning[-2] &&
|
382
|
+
(@partitioning[-2].last.is_a?(::Neo4j::Core::QueryClauses::WithClause) ||
|
383
|
+
@partitioning[-2].last.is_a?(::Neo4j::Core::QueryClauses::OrderClause))
|
384
|
+
end
|
385
|
+
|
386
|
+
def clause_is_with_following_order_or_limit?(clause)
|
387
|
+
clause.is_a?(::Neo4j::Core::QueryClauses::WithClause) &&
|
388
|
+
@partitioning[-2] && @partitioning[-2].any? { |c| self.class.clause_is_order_or_limit?(c) }
|
389
|
+
end
|
390
|
+
|
391
|
+
def self.clause_is_order_or_limit?(clause)
|
392
|
+
clause.is_a?(::Neo4j::Core::QueryClauses::OrderClause) ||
|
393
|
+
clause.is_a?(::Neo4j::Core::QueryClauses::LimitClause)
|
394
|
+
end
|
395
|
+
end
|
396
|
+
|
397
|
+
def merge_params
|
398
|
+
@clauses.compact!
|
399
|
+
@merge_params ||= @clauses.inject(@_params) { |params, clause| params.merge!(clause.params) }
|
344
400
|
end
|
345
401
|
end
|
346
402
|
end
|