neo4j-core 6.1.6 → 7.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.
- 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
|
|