neo4j-core 6.1.6 → 7.0.0.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -9
- data/README.md +48 -0
- data/lib/neo4j-core.rb +23 -0
- data/lib/neo4j-core/helpers.rb +8 -0
- data/lib/neo4j-core/query.rb +23 -20
- data/lib/neo4j-core/query_clauses.rb +18 -32
- data/lib/neo4j-core/query_find_in_batches.rb +3 -1
- data/lib/neo4j-core/version.rb +1 -1
- data/lib/neo4j-embedded/cypher_response.rb +4 -0
- data/lib/neo4j-embedded/embedded_database.rb +3 -5
- data/lib/neo4j-embedded/embedded_node.rb +4 -4
- data/lib/neo4j-embedded/embedded_session.rb +21 -10
- data/lib/neo4j-embedded/embedded_transaction.rb +4 -10
- data/lib/neo4j-server/cypher_node.rb +5 -4
- data/lib/neo4j-server/cypher_relationship.rb +3 -3
- data/lib/neo4j-server/cypher_response.rb +4 -0
- data/lib/neo4j-server/cypher_session.rb +31 -22
- data/lib/neo4j-server/cypher_transaction.rb +23 -15
- data/lib/neo4j-server/resource.rb +3 -4
- data/lib/neo4j/core/cypher_session.rb +17 -9
- data/lib/neo4j/core/cypher_session/adaptors.rb +116 -33
- data/lib/neo4j/core/cypher_session/adaptors/bolt.rb +331 -0
- data/lib/neo4j/core/cypher_session/adaptors/bolt/chunk_writer_io.rb +76 -0
- data/lib/neo4j/core/cypher_session/adaptors/bolt/pack_stream.rb +288 -0
- data/lib/neo4j/core/cypher_session/adaptors/embedded.rb +60 -29
- data/lib/neo4j/core/cypher_session/adaptors/has_uri.rb +63 -0
- data/lib/neo4j/core/cypher_session/adaptors/http.rb +123 -119
- data/lib/neo4j/core/cypher_session/responses.rb +17 -2
- data/lib/neo4j/core/cypher_session/responses/bolt.rb +135 -0
- data/lib/neo4j/core/cypher_session/responses/embedded.rb +46 -11
- data/lib/neo4j/core/cypher_session/responses/http.rb +49 -40
- data/lib/neo4j/core/cypher_session/transactions.rb +33 -0
- data/lib/neo4j/core/cypher_session/transactions/bolt.rb +36 -0
- data/lib/neo4j/core/cypher_session/transactions/embedded.rb +32 -0
- data/lib/neo4j/core/cypher_session/transactions/http.rb +52 -0
- data/lib/neo4j/core/instrumentable.rb +2 -2
- data/lib/neo4j/core/label.rb +182 -0
- data/lib/neo4j/core/node.rb +8 -3
- data/lib/neo4j/core/relationship.rb +12 -4
- data/lib/neo4j/entity_equality.rb +1 -1
- data/lib/neo4j/session.rb +4 -5
- data/lib/neo4j/transaction.rb +108 -72
- data/neo4j-core.gemspec +6 -6
- metadata +34 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d35477edf97f10ae13b42128f88351fd5823160f
|
4
|
+
data.tar.gz: ef4e066f6673584c3863f0a68a7c0f78034755eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6855bc2443d440660c73c1f8d0270abf0ca18dca819cbae37f57a2a277e0ef9c49d166209f8377c87397d6ed1314eda0cba700e3b729c764f2b3077c38770476
|
7
|
+
data.tar.gz: 0887b3a29ca9c0ce06c1352df53824678f2c571a15fd0b89da9383374af3faab6add251f927079689695d323e412c1d00721e77eb23917331b78972014f72b80
|
data/Gemfile
CHANGED
@@ -5,23 +5,18 @@ gemspec
|
|
5
5
|
# gem 'neo4j-advanced', '>= 1.8.1', '< 2.0', :require => false
|
6
6
|
# gem 'neo4j-enterprise', '>= 1.8.1', '< 2.0', :require => false
|
7
7
|
|
8
|
-
gem '
|
8
|
+
gem 'tins', '< 1.7' if RUBY_VERSION.to_f < 2.0
|
9
9
|
|
10
10
|
group 'development' do
|
11
|
-
gem '
|
12
|
-
gem '
|
13
|
-
if RUBY_VERSION.to_f < 2.0
|
14
|
-
gem 'overcommit', '< 0.35.0'
|
15
|
-
else
|
16
|
-
gem 'overcommit'
|
17
|
-
end
|
11
|
+
gem 'guard-rspec', require: false if RUBY_PLATFORM != 'java'
|
12
|
+
gem 'overcommit'
|
18
13
|
end
|
19
14
|
|
20
15
|
group 'test' do
|
21
16
|
gem 'coveralls', require: false
|
22
17
|
gem 'simplecov-html', require: false
|
23
|
-
gem 'tins', '< 1.7' if RUBY_VERSION.to_f < 2.0
|
24
18
|
gem 'rspec', '~> 3.0'
|
25
19
|
gem 'rspec-its'
|
26
20
|
gem 'dotenv'
|
21
|
+
gem 'activesupport', '~> 4.0'
|
27
22
|
end
|
data/README.md
CHANGED
@@ -3,6 +3,54 @@
|
|
3
3
|
A simple Ruby wrapper around the Neo4j graph database that works with the server and embedded Neo4j API. This gem can be used both from JRuby and normal MRI.
|
4
4
|
It can be used standalone without the neo4j gem.
|
5
5
|
|
6
|
+
## Basic usage
|
7
|
+
|
8
|
+
### Executing Cypher queries
|
9
|
+
|
10
|
+
To make a basic connection to Neo4j to execute Cypher queries, first choose an adaptor. Adaptors for HTTP and Embedded mode (jRuby only) are available (support for Neo4j 3.0's [Bolt protocol](http://alpha.neohq.net/docs/server-manual/bolt.html) is planned). You can create an adaptor like:
|
11
|
+
|
12
|
+
http_adaptor = Neo4j::Core::CypherSession::Adaptors::HTTP.new('http://neo4j:pass@localhost:7474')
|
13
|
+
|
14
|
+
# or
|
15
|
+
|
16
|
+
neo4j_adaptor = Neo4j::Core::CypherSession::Adaptors::Embedded.new('/file/path/to/graph.db')
|
17
|
+
|
18
|
+
Once you have an adaptor you can create a session like so:
|
19
|
+
|
20
|
+
neo4j_session = Neo4j::Core::CypherSession.new(http_adaptor)
|
21
|
+
|
22
|
+
From there you can make queries with a Cypher string:
|
23
|
+
|
24
|
+
# Basic query
|
25
|
+
neo4j_session.query('MATCH (n) RETURN n LIMIT 10')
|
26
|
+
|
27
|
+
# Query with parameters
|
28
|
+
neo4j_session.query('MATCH (n) RETURN n LIMIT {limit}', limit: 10)
|
29
|
+
|
30
|
+
Or via the `Neo4j::Core::Query` class
|
31
|
+
|
32
|
+
query_obj = Neo4j::Core::Query.new.match(:n).return(:n).limit(10)
|
33
|
+
|
34
|
+
neo4j_session.query(query_obj)
|
35
|
+
|
36
|
+
Making multiple queries with one request is support with the HTTP Adaptor:
|
37
|
+
|
38
|
+
results = neo4j_session.queries do
|
39
|
+
append 'MATCH (n:Foo) RETURN n LIMIT 10'
|
40
|
+
append 'MATCH (n:Bar) RETURN n LIMIT 5'
|
41
|
+
end
|
42
|
+
|
43
|
+
results[0] # results of first query
|
44
|
+
results[1] # results of second query
|
45
|
+
|
46
|
+
When doing batched queries, there is also a shortcut for getting a new `Neo4j::Core::Query`:
|
47
|
+
|
48
|
+
results = neo4j_session.queries do
|
49
|
+
append query.match(:n).return(:n).limit(10)
|
50
|
+
end
|
51
|
+
|
52
|
+
results[0] # result
|
53
|
+
|
6
54
|
## Documentation
|
7
55
|
|
8
56
|
### 3.0+ Documentation:
|
data/lib/neo4j-core.rb
CHANGED
@@ -24,3 +24,26 @@ require 'neo4j/transaction'
|
|
24
24
|
|
25
25
|
require 'rake'
|
26
26
|
require 'neo4j/rake_tasks'
|
27
|
+
|
28
|
+
require 'logger'
|
29
|
+
|
30
|
+
module Neo4j
|
31
|
+
module Core
|
32
|
+
ORIGINAL_FORMATTER = ::Logger::Formatter.new
|
33
|
+
|
34
|
+
def self.logger(stream = STDOUT)
|
35
|
+
@logger ||= Logger.new(stream).tap do |logger|
|
36
|
+
logger.formatter = method(:formatter)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.formatter(severity, datetime, progname, msg)
|
41
|
+
output = ''
|
42
|
+
if Thread.current != Thread.main
|
43
|
+
output += "#{ANSI::YELLOW}Thread: #{Thread.current.object_id}: #{ANSI::CLEAR}"
|
44
|
+
end
|
45
|
+
output += msg
|
46
|
+
ORIGINAL_FORMATTER.call(severity, datetime, progname, output)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/neo4j-core/helpers.rb
CHANGED
@@ -18,6 +18,14 @@ module Neo4j
|
|
18
18
|
def self.using_new_session?
|
19
19
|
ENV.key?('NEW_NEO4J_SESSIONS')
|
20
20
|
end
|
21
|
+
|
22
|
+
def self.wrapping_level(level = nil)
|
23
|
+
if level.nil?
|
24
|
+
@wrapping_level || :core_entity
|
25
|
+
else
|
26
|
+
@wrapping_level = level
|
27
|
+
end
|
28
|
+
end
|
21
29
|
end
|
22
30
|
end
|
23
31
|
end
|
data/lib/neo4j-core/query.rb
CHANGED
@@ -158,10 +158,11 @@ module Neo4j
|
|
158
158
|
# DETACH DELETE clause
|
159
159
|
# @return [Query]
|
160
160
|
|
161
|
-
METHODS = %w(start match optional_match
|
162
|
-
BREAK_METHODS = %(with
|
161
|
+
METHODS = %w(start match optional_match using where create create_unique merge set on_create_set on_match_set remove unwind delete detach_delete with return order skip limit)
|
162
|
+
BREAK_METHODS = %(with)
|
163
163
|
|
164
164
|
CLAUSIFY_CLAUSE = proc { |method| const_get(method.to_s.split('_').map(&:capitalize).join + 'Clause') }
|
165
|
+
|
165
166
|
CLAUSES = METHODS.map(&CLAUSIFY_CLAUSE)
|
166
167
|
|
167
168
|
METHODS.each_with_index do |clause, i|
|
@@ -175,8 +176,8 @@ module Neo4j
|
|
175
176
|
end
|
176
177
|
end
|
177
178
|
|
178
|
-
|
179
|
-
|
179
|
+
alias offset skip
|
180
|
+
alias order_by order
|
180
181
|
|
181
182
|
# Clears out previous order clauses and allows only for those specified by args
|
182
183
|
def reorder(*args)
|
@@ -235,16 +236,16 @@ module Neo4j
|
|
235
236
|
def response
|
236
237
|
return @response if @response
|
237
238
|
|
238
|
-
cypher = to_cypher
|
239
|
-
pretty_cypher = to_cypher(pretty: true) if self.class.pretty_cypher
|
240
|
-
|
241
239
|
@response = if session_is_new_api?
|
242
|
-
@session.query(self)
|
240
|
+
@session.query(self, transaction: Transaction.current_for(@session), wrap_level: (:core_entity if unwrapped?))
|
243
241
|
else
|
244
|
-
@session._query(
|
242
|
+
@session._query(to_cypher, merge_params,
|
243
|
+
context: @options[:context], pretty_cypher: (pretty_cypher if self.class.pretty_cypher)).tap(&method(:raise_if_cypher_error!))
|
245
244
|
end
|
245
|
+
end
|
246
246
|
|
247
|
-
|
247
|
+
def raise_if_cypher_error!(response)
|
248
|
+
response.raise_cypher_error if response.respond_to?(:error?) && response.error?
|
248
249
|
end
|
249
250
|
|
250
251
|
def match_nodes(hash, optional_match = false)
|
@@ -269,9 +270,11 @@ module Neo4j
|
|
269
270
|
|
270
271
|
def each
|
271
272
|
response = self.response
|
272
|
-
if response.is_a?(Neo4j::Server::CypherResponse)
|
273
|
+
if defined?(Neo4j::Server::CypherResponse) && response.is_a?(Neo4j::Server::CypherResponse)
|
273
274
|
response.unwrapped! if unwrapped?
|
274
275
|
response.to_node_enumeration
|
276
|
+
elsif defined?(Neo4j::Core::CypherSession::Result) && response.is_a?(Neo4j::Core::CypherSession::Result)
|
277
|
+
response.to_a
|
275
278
|
else
|
276
279
|
Neo4j::Embedded::ResultWrapper.new(response, to_cypher, unwrapped?)
|
277
280
|
end.each { |object| yield object }
|
@@ -307,8 +310,7 @@ module Neo4j
|
|
307
310
|
query = return_query(columns)
|
308
311
|
columns = query.response.columns
|
309
312
|
|
310
|
-
|
311
|
-
when 1
|
313
|
+
if columns.size == 1
|
312
314
|
column = columns[0]
|
313
315
|
query.map { |row| row[column] }
|
314
316
|
else
|
@@ -346,7 +348,7 @@ module Neo4j
|
|
346
348
|
cypher_string = "CYPHER #{@options[:parser]} #{cypher_string}" if @options[:parser]
|
347
349
|
cypher_string.tap(&:strip!)
|
348
350
|
end
|
349
|
-
|
351
|
+
alias cypher to_cypher
|
350
352
|
|
351
353
|
def pretty_cypher
|
352
354
|
to_cypher(pretty: true)
|
@@ -481,17 +483,18 @@ module Neo4j
|
|
481
483
|
@partitioning[-2] && @partitioning[-2].any? { |c| self.class.clause_is_order_or_limit?(c) }
|
482
484
|
end
|
483
485
|
|
484
|
-
|
485
|
-
|
486
|
-
clause.is_a?(::Neo4j::Core::QueryClauses::
|
486
|
+
class << self
|
487
|
+
def clause_is_order_or_limit?(clause)
|
488
|
+
clause.is_a?(::Neo4j::Core::QueryClauses::OrderClause) ||
|
489
|
+
clause.is_a?(::Neo4j::Core::QueryClauses::LimitClause)
|
490
|
+
end
|
487
491
|
end
|
488
492
|
end
|
489
493
|
|
490
494
|
# SHOULD BE DEPRECATED
|
491
495
|
def merge_params
|
492
|
-
@clauses.compact!
|
493
|
-
@
|
494
|
-
@params.to_hash
|
496
|
+
@merge_params_base ||= @clauses.compact.inject({}) { |params, clause| params.merge!(clause.params) }
|
497
|
+
@params.to_hash.merge(@merge_params_base)
|
495
498
|
end
|
496
499
|
end
|
497
500
|
end
|
@@ -90,8 +90,8 @@ module Neo4j
|
|
90
90
|
when Hash
|
91
91
|
if value.values.map(&:class) == [Hash]
|
92
92
|
value.first.first
|
93
|
-
|
94
|
-
key
|
93
|
+
elsif !_use_key_for_var?(value, prefer)
|
94
|
+
key
|
95
95
|
end
|
96
96
|
else
|
97
97
|
fail ArgError, value
|
@@ -144,7 +144,7 @@ module Neo4j
|
|
144
144
|
keyword
|
145
145
|
end
|
146
146
|
|
147
|
-
"#{final_keyword} #{string}" if string.
|
147
|
+
"#{final_keyword} #{string}" if !string.empty?
|
148
148
|
end
|
149
149
|
|
150
150
|
def clause_string(clauses, pretty)
|
@@ -162,6 +162,14 @@ module Neo4j
|
|
162
162
|
def clause_color
|
163
163
|
ANSI::CYAN
|
164
164
|
end
|
165
|
+
|
166
|
+
def from_key_and_single_value(key, value)
|
167
|
+
if value.to_sym == :neo_id
|
168
|
+
"ID(#{key})"
|
169
|
+
else
|
170
|
+
"#{key}.#{value}"
|
171
|
+
end
|
172
|
+
end
|
165
173
|
end
|
166
174
|
|
167
175
|
def self.paramaterize_key!(key)
|
@@ -211,7 +219,7 @@ module Neo4j
|
|
211
219
|
label_arg = label_arg.to_s
|
212
220
|
label_arg.strip!
|
213
221
|
if !label_arg.empty? && label_arg[0] != ':'
|
214
|
-
label_arg = "`#{label_arg}`" unless label_arg
|
222
|
+
label_arg = "`#{label_arg}`" unless label_arg[' ']
|
215
223
|
label_arg = ":#{label_arg}"
|
216
224
|
end
|
217
225
|
label_arg
|
@@ -221,10 +229,10 @@ module Neo4j
|
|
221
229
|
return '' if not attributes
|
222
230
|
|
223
231
|
attributes_string = attributes.map do |key, value|
|
224
|
-
if value.to_s
|
232
|
+
if value.to_s =~ /^{.+}$/
|
225
233
|
"#{key}: #{value}"
|
226
234
|
else
|
227
|
-
param_key = "#{prefix}#{key}".gsub(
|
235
|
+
param_key = "#{prefix}#{key}".gsub(/:+/, '_')
|
228
236
|
param_key = add_param(param_key, value)
|
229
237
|
"#{key}: {#{param_key}}"
|
230
238
|
end
|
@@ -337,24 +345,6 @@ module Neo4j
|
|
337
345
|
end
|
338
346
|
end
|
339
347
|
|
340
|
-
class CallClause < Clause
|
341
|
-
KEYWORD = 'CALL'
|
342
|
-
|
343
|
-
def from_string(value)
|
344
|
-
value
|
345
|
-
end
|
346
|
-
|
347
|
-
class << self
|
348
|
-
def clause_strings(clauses)
|
349
|
-
clauses.map!(&:value)
|
350
|
-
end
|
351
|
-
|
352
|
-
def clause_join
|
353
|
-
" #{KEYWORD} "
|
354
|
-
end
|
355
|
-
end
|
356
|
-
end
|
357
|
-
|
358
348
|
class MatchClause < Clause
|
359
349
|
KEYWORD = 'MATCH'
|
360
350
|
|
@@ -511,13 +501,13 @@ module Neo4j
|
|
511
501
|
def from_key_and_value(key, value)
|
512
502
|
case value
|
513
503
|
when String, Symbol
|
514
|
-
|
504
|
+
self.class.from_key_and_single_value(key, value)
|
515
505
|
when Array
|
516
506
|
value.map do |v|
|
517
|
-
v.is_a?(Hash) ? from_key_and_value(key, v) :
|
507
|
+
v.is_a?(Hash) ? from_key_and_value(key, v) : self.class.from_key_and_single_value(key, v)
|
518
508
|
end
|
519
509
|
when Hash
|
520
|
-
value.map { |k, v| "#{key
|
510
|
+
value.map { |k, v| "#{self.class.from_key_and_single_value(key, k)} #{v.upcase}" }
|
521
511
|
end
|
522
512
|
end
|
523
513
|
|
@@ -708,11 +698,7 @@ module Neo4j
|
|
708
698
|
from_key_and_value(key, v)
|
709
699
|
end.join(Clause::COMMA_SPACE)
|
710
700
|
when String, Symbol
|
711
|
-
|
712
|
-
"ID(#{key})"
|
713
|
-
else
|
714
|
-
"#{key}.#{value}"
|
715
|
-
end
|
701
|
+
self.class.from_key_and_single_value(key, value)
|
716
702
|
else
|
717
703
|
fail ArgError, value
|
718
704
|
end
|
@@ -18,7 +18,9 @@ module Neo4j
|
|
18
18
|
|
19
19
|
break if records_size < batch_size
|
20
20
|
|
21
|
-
|
21
|
+
primary_key_var = Neo4j::Core::QueryClauses::Clause.from_key_and_single_value(node_var, prop_var)
|
22
|
+
records = query.where("#{primary_key_var} > {primary_key_offset}")
|
23
|
+
.params(primary_key_offset: primary_key_offset).to_a
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
data/lib/neo4j-core/version.rb
CHANGED
@@ -6,11 +6,9 @@ module Neo4j
|
|
6
6
|
|
7
7
|
class << self
|
8
8
|
def connect(db_location, config = {})
|
9
|
-
if Neo4j::Session.current.respond_to?(:db_location) && Neo4j::Session.current.db_location == db_location
|
10
|
-
|
11
|
-
|
12
|
-
EmbeddedSession.new(db_location, config)
|
13
|
-
end
|
9
|
+
return Neo4j::Session.current if Neo4j::Session.current.respond_to?(:db_location) && Neo4j::Session.current.db_location == db_location
|
10
|
+
|
11
|
+
EmbeddedSession.new(db_location, config)
|
14
12
|
end
|
15
13
|
|
16
14
|
def create_db(db_location)
|
@@ -16,8 +16,8 @@ module Neo4j
|
|
16
16
|
'Enumerable<Neo4j::Relationship>'
|
17
17
|
end
|
18
18
|
|
19
|
-
def each
|
20
|
-
@node._rels(@match).each { |r|
|
19
|
+
def each
|
20
|
+
@node._rels(@match).each { |r| yield(r.wrapper) }
|
21
21
|
end
|
22
22
|
tx_methods :each
|
23
23
|
|
@@ -39,8 +39,8 @@ module Neo4j
|
|
39
39
|
'Enumerable<Neo4j::Node>'
|
40
40
|
end
|
41
41
|
|
42
|
-
def each
|
43
|
-
@node._rels(@match).each { |r|
|
42
|
+
def each
|
43
|
+
@node._rels(@match).each { |r| yield(r.other_node(@node)) }
|
44
44
|
end
|
45
45
|
tx_methods :each
|
46
46
|
|
@@ -68,21 +68,32 @@ module Neo4j
|
|
68
68
|
Java::OrgNeo4jTest::ImpermanentGraphDatabase
|
69
69
|
end
|
70
70
|
|
71
|
-
def begin_tx
|
72
|
-
if Neo4j::Transaction.current
|
73
|
-
# Handle nested transaction "placebo transaction"
|
74
|
-
Neo4j::Transaction.current.push_nested!
|
75
|
-
else
|
76
|
-
Neo4j::Embedded::EmbeddedTransaction.new(@graph_db.begin_tx)
|
77
|
-
end
|
78
|
-
Neo4j::Transaction.current
|
79
|
-
end
|
80
|
-
|
81
71
|
def close
|
82
72
|
super
|
83
73
|
shutdown
|
84
74
|
end
|
85
75
|
|
76
|
+
def self.transaction_class
|
77
|
+
Neo4j::Embedded::EmbeddedTransaction
|
78
|
+
end
|
79
|
+
|
80
|
+
# Duplicate of CypherSession::Adaptor::Base#transaction
|
81
|
+
def transaction
|
82
|
+
return self.class.transaction_class.new(self) if !block_given?
|
83
|
+
|
84
|
+
begin
|
85
|
+
tx = transaction
|
86
|
+
|
87
|
+
yield tx
|
88
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
89
|
+
tx.mark_failed
|
90
|
+
|
91
|
+
raise e
|
92
|
+
ensure
|
93
|
+
tx.close
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
86
97
|
def shutdown
|
87
98
|
@graph_db && @graph_db.shutdown
|
88
99
|
|