neo4j 9.6.2 → 10.0.0.pre.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/CHANGELOG.md +0 -13
- data/CONTRIBUTORS +4 -0
- data/Gemfile +2 -33
- data/lib/neo4j.rb +6 -2
- data/lib/neo4j/active_base.rb +19 -22
- data/lib/neo4j/active_node/has_n.rb +1 -1
- data/lib/neo4j/active_node/labels.rb +1 -11
- data/lib/neo4j/active_node/node_wrapper.rb +1 -1
- data/lib/neo4j/active_node/query/query_proxy_methods_of_mass_updating.rb +1 -1
- data/lib/neo4j/active_rel/rel_wrapper.rb +2 -2
- data/lib/neo4j/ansi.rb +14 -0
- data/lib/neo4j/core.rb +14 -0
- data/lib/neo4j/core/connection_failed_error.rb +6 -0
- data/lib/neo4j/core/cypher_error.rb +37 -0
- data/lib/neo4j/core/driver.rb +83 -0
- data/lib/neo4j/core/has_uri.rb +63 -0
- data/lib/neo4j/core/instrumentable.rb +36 -0
- data/lib/neo4j/core/label.rb +158 -0
- data/lib/neo4j/core/logging.rb +44 -0
- data/lib/neo4j/core/node.rb +23 -0
- data/lib/neo4j/core/querable.rb +88 -0
- data/lib/neo4j/core/query.rb +487 -0
- data/lib/neo4j/core/query_builder.rb +32 -0
- data/lib/neo4j/core/query_clauses.rb +727 -0
- data/lib/neo4j/core/query_find_in_batches.rb +49 -0
- data/lib/neo4j/core/relationship.rb +13 -0
- data/lib/neo4j/core/responses.rb +50 -0
- data/lib/neo4j/core/result.rb +33 -0
- data/lib/neo4j/core/schema.rb +30 -0
- data/lib/neo4j/core/schema_errors.rb +12 -0
- data/lib/neo4j/core/wrappable.rb +30 -0
- data/lib/neo4j/migration.rb +2 -2
- data/lib/neo4j/migrations/base.rb +1 -1
- data/lib/neo4j/model_schema.rb +2 -2
- data/lib/neo4j/railtie.rb +8 -52
- data/lib/neo4j/schema/operation.rb +1 -1
- data/lib/neo4j/shared.rb +1 -1
- data/lib/neo4j/shared/property.rb +1 -1
- data/lib/neo4j/tasks/migration.rake +5 -4
- data/lib/neo4j/transaction.rb +137 -0
- data/lib/neo4j/version.rb +1 -1
- data/neo4j.gemspec +5 -5
- metadata +59 -26
- data/bin/neo4j-jars +0 -33
- data/lib/neo4j/active_base/session_registry.rb +0 -12
- data/lib/neo4j/session_manager.rb +0 -78
@@ -0,0 +1,49 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module QueryFindInBatches
|
4
|
+
def find_in_batches(node_var, prop_var, options = {})
|
5
|
+
validate_find_in_batches_options!(options)
|
6
|
+
|
7
|
+
batch_size = options.delete(:batch_size) || 1000
|
8
|
+
|
9
|
+
query = reorder(node_var => prop_var).limit(batch_size)
|
10
|
+
|
11
|
+
records = query.to_a
|
12
|
+
|
13
|
+
while records.any?
|
14
|
+
records_size = records.size
|
15
|
+
primary_key_offset = primary_key_offset(records.last, node_var, prop_var)
|
16
|
+
|
17
|
+
yield records
|
18
|
+
|
19
|
+
break if records_size < batch_size
|
20
|
+
|
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
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def find_each(*args, &block)
|
28
|
+
find_in_batches(*args) { |batch| batch.each(&block) }
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def validate_find_in_batches_options!(options)
|
34
|
+
invalid_keys = options.keys.map(&:to_sym) - [:batch_size]
|
35
|
+
fail ArgumentError, "Invalid keys: #{invalid_keys.join(', ')}" if not invalid_keys.empty?
|
36
|
+
end
|
37
|
+
|
38
|
+
def primary_key_offset(last_record, node_var, prop_var)
|
39
|
+
last_record.send(node_var).send(prop_var)
|
40
|
+
rescue NoMethodError
|
41
|
+
begin
|
42
|
+
last_record.send(node_var).properties[prop_var.to_sym]
|
43
|
+
rescue NoMethodError
|
44
|
+
last_record.send("#{node_var}.#{prop_var}") # In case we're explicitly returning it
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'neo4j/core/wrappable'
|
2
|
+
|
3
|
+
module Neo4j
|
4
|
+
module Core
|
5
|
+
module Relationship
|
6
|
+
def props; properties; end
|
7
|
+
def neo_id; id; end
|
8
|
+
def start_node_neo_id; start_node_id; end
|
9
|
+
def end_node_neo_id; end_node_id; end
|
10
|
+
def rel_type; type; end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'neo4j/core/result'
|
2
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
3
|
+
|
4
|
+
module Neo4j
|
5
|
+
module Core
|
6
|
+
module Responses
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
mattr_accessor :wrap_level
|
11
|
+
end
|
12
|
+
|
13
|
+
class_methods do
|
14
|
+
def result_from_data(entities_data)
|
15
|
+
rows = entities_data.map do |entity_data|
|
16
|
+
wrap(entity_data.values)
|
17
|
+
end
|
18
|
+
|
19
|
+
Neo4j::Core::Result.new(entities_data.keys, rows)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def wrap(value)
|
25
|
+
case value
|
26
|
+
when Neo4j::Driver::Types::Entity
|
27
|
+
wrap_by_level(value)
|
28
|
+
when Neo4j::Driver::Types::Path
|
29
|
+
value
|
30
|
+
when Hash
|
31
|
+
value.map { |key, val| [key, wrap(val)] }.to_h
|
32
|
+
when Enumerable
|
33
|
+
value.map(&method(:wrap))
|
34
|
+
else
|
35
|
+
value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def wrap_by_level(entity)
|
40
|
+
case wrap_level
|
41
|
+
when :core_entity
|
42
|
+
entity
|
43
|
+
else
|
44
|
+
entity.wrap
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
class Result
|
4
|
+
attr_reader :columns, :rows
|
5
|
+
|
6
|
+
def initialize(columns, rows)
|
7
|
+
@columns = columns.map(&:to_sym)
|
8
|
+
@rows = rows
|
9
|
+
@struct_class = Struct.new(:index, *@columns)
|
10
|
+
end
|
11
|
+
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
def each
|
15
|
+
structs.each do |struct|
|
16
|
+
yield struct
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def structs
|
21
|
+
@structs ||= rows.each_with_index.map do |row, index|
|
22
|
+
@struct_class.new(index, *row)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def hashes
|
27
|
+
@hashes ||= rows.map do |row|
|
28
|
+
Hash[@columns.zip(row)]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module Schema
|
4
|
+
def version
|
5
|
+
result = query('CALL dbms.components()', {}, skip_instrumentation: true)
|
6
|
+
|
7
|
+
# BTW: community / enterprise could be retrieved via `result.first.edition`
|
8
|
+
result.first.versions[0]
|
9
|
+
end
|
10
|
+
|
11
|
+
def indexes
|
12
|
+
result = query('CALL db.indexes()', {}, skip_instrumentation: true)
|
13
|
+
|
14
|
+
result.map do |row|
|
15
|
+
label, property = row.description.match(/INDEX ON :([^\(]+)\(([^\)]+)\)/)[1, 2]
|
16
|
+
{ type: row.type.to_sym, label: label.to_sym, properties: [property.to_sym], state: row.state.to_sym }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def constraints
|
21
|
+
result = query('CALL db.indexes()', {}, skip_instrumentation: true)
|
22
|
+
|
23
|
+
result.select { |row| row.type == 'node_unique_property' }.map do |row|
|
24
|
+
label, property = row.description.match(/INDEX ON :([^\(]+)\(([^\)]+)\)/)[1, 2]
|
25
|
+
{ type: :uniqueness, label: label.to_sym, properties: [property.to_sym] }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Neo4j
|
2
|
+
module Core
|
3
|
+
module Wrappable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def wrap
|
7
|
+
self.class.wrap(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
class_methods do
|
11
|
+
def wrapper_callback(proc)
|
12
|
+
fail 'Callback already specified!' if @wrapper_callback
|
13
|
+
@wrapper_callback = proc
|
14
|
+
end
|
15
|
+
|
16
|
+
def clear_wrapper_callback
|
17
|
+
@wrapper_callback = nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def wrap(node)
|
21
|
+
if @wrapper_callback
|
22
|
+
@wrapper_callback.call(node)
|
23
|
+
else
|
24
|
+
node
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/neo4j/migration.rb
CHANGED
@@ -28,7 +28,7 @@ module Neo4j
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def query(*args)
|
31
|
-
Neo4j::ActiveBase.
|
31
|
+
Neo4j::ActiveBase.current_driver.query(*args)
|
32
32
|
end
|
33
33
|
|
34
34
|
class AddIdProperty < Neo4j::Migration
|
@@ -115,7 +115,7 @@ MESSAGE
|
|
115
115
|
# def id_batch_set(label, id_property, new_ids, count)
|
116
116
|
# tx = Neo4j::ActiveBase.new_transaction
|
117
117
|
|
118
|
-
# Neo4j::ActiveBase.
|
118
|
+
# Neo4j::ActiveBase.current_driver.query("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
|
119
119
|
# with COLLECT(n) as nodes, #{new_ids} as ids
|
120
120
|
# FOREACH(i in range(0,#{count - 1})|
|
121
121
|
# FOREACH(node in [nodes[i]]|
|
@@ -67,7 +67,7 @@ module Neo4j
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def log_queries
|
70
|
-
subscriber = Neo4j::
|
70
|
+
subscriber = Neo4j::Transaction.subscribe_to_query(&method(:output))
|
71
71
|
yield
|
72
72
|
ensure
|
73
73
|
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
|
data/lib/neo4j/model_schema.rb
CHANGED
@@ -32,7 +32,7 @@ module Neo4j
|
|
32
32
|
def model_constraints
|
33
33
|
return @model_constraints if @model_constraints
|
34
34
|
|
35
|
-
constraints = Neo4j::
|
35
|
+
constraints = Neo4j::Transaction.constraints.each_with_object({}) do |row, result|
|
36
36
|
result[row[:label]] ||= []
|
37
37
|
result[row[:label]] << row[:properties]
|
38
38
|
end
|
@@ -43,7 +43,7 @@ module Neo4j
|
|
43
43
|
def model_indexes
|
44
44
|
return @model_indexes if @model_indexes
|
45
45
|
|
46
|
-
indexes = Neo4j::
|
46
|
+
indexes = Neo4j::Transaction.indexes.each_with_object({}) do |row, result|
|
47
47
|
result[row[:label]] ||= []
|
48
48
|
result[row[:label]] << row[:properties]
|
49
49
|
end
|
data/lib/neo4j/railtie.rb
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
require 'active_support/notifications'
|
2
2
|
require 'rails/railtie'
|
3
|
-
require 'neo4j/session_manager'
|
4
3
|
# Need the action_dispatch railtie to have action_dispatch.rescue_responses initialized correctly
|
5
4
|
require 'action_dispatch/railtie'
|
6
|
-
require 'neo4j/core/
|
5
|
+
require 'neo4j/core/driver'
|
7
6
|
|
8
7
|
module Neo4j
|
9
8
|
class Railtie < ::Rails::Railtie
|
@@ -59,49 +58,15 @@ module Neo4j
|
|
59
58
|
end
|
60
59
|
|
61
60
|
def setup!(neo4j_config = empty_config)
|
62
|
-
|
63
|
-
type, url, path, options = final_session_config!(neo4j_config).values_at(:type, :url, :path, :options)
|
64
|
-
type ||= default_session_type
|
61
|
+
url, path, options = final_session_config!(neo4j_config).values_at(:url, :path, :options)
|
65
62
|
options ||= {}
|
66
|
-
register_neo4j_cypher_logging
|
63
|
+
register_neo4j_cypher_logging
|
67
64
|
|
68
|
-
Neo4j::
|
69
|
-
url || path || default_session_path_or_url,
|
70
|
-
wait_for_connection,
|
71
|
-
options)
|
65
|
+
Neo4j::ActiveBase.new_driver( url || path || default_session_path_or_url, options)
|
72
66
|
end
|
73
67
|
|
74
68
|
def final_session_config!(neo4j_config)
|
75
|
-
|
76
|
-
|
77
|
-
(neo4j_config[:session].empty? ? yaml_config_data : neo4j_config[:session]).dup.tap do |result|
|
78
|
-
result[:type] ||= URI(result[:url]).scheme if result[:url]
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
def support_deprecated_session_configs!(neo4j_config)
|
83
|
-
if neo4j_config.sessions.present?
|
84
|
-
ActiveSupport::Deprecation.warn('neo4j.config.sessions is deprecated, please use neo4j.config.session (not an array)')
|
85
|
-
neo4j_config[:session] = neo4j_config.sessions[0] if neo4j_config[:session].empty?
|
86
|
-
end
|
87
|
-
|
88
|
-
%w(type path url options).each do |key|
|
89
|
-
value = neo4j_config.send("session_#{key}")
|
90
|
-
if value.present?
|
91
|
-
ActiveSupport::Deprecation.warn("neo4j.config.session_#{key} is deprecated, please use neo4j.config.session.#{key}")
|
92
|
-
neo4j_config[:session][key] = value
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def default_session_type
|
98
|
-
if ENV['NEO4J_URL']
|
99
|
-
scheme = URI(ENV['NEO4J_URL']).scheme
|
100
|
-
fail "Invalid scheme for NEO4J_URL: #{scheme}" if !%w(http https bolt).include?(scheme)
|
101
|
-
scheme == 'https' ? 'http' : scheme
|
102
|
-
else
|
103
|
-
ENV['NEO4J_TYPE'] || :http
|
104
|
-
end.to_sym
|
69
|
+
(neo4j_config[:session].empty? ? yaml_config_data : neo4j_config[:session]).dup
|
105
70
|
end
|
106
71
|
|
107
72
|
def default_session_path_or_url
|
@@ -123,7 +88,7 @@ module Neo4j
|
|
123
88
|
end.detect(&:exist?)
|
124
89
|
end
|
125
90
|
|
126
|
-
def register_neo4j_cypher_logging
|
91
|
+
def register_neo4j_cypher_logging
|
127
92
|
return if @neo4j_cypher_logging_registered
|
128
93
|
|
129
94
|
Neo4j::Core::Query.pretty_cypher = Neo4j::Config[:pretty_logged_cypher_queries]
|
@@ -131,19 +96,10 @@ module Neo4j
|
|
131
96
|
logger_proc = ->(message) do
|
132
97
|
(Neo4j::Config[:logger] ||= Rails.logger).debug message
|
133
98
|
end
|
134
|
-
Neo4j::
|
135
|
-
|
99
|
+
Neo4j::Transaction.subscribe_to_query(&logger_proc)
|
100
|
+
Neo4j::Transaction.subscribe_to_request(&logger_proc)
|
136
101
|
|
137
102
|
@neo4j_cypher_logging_registered = true
|
138
103
|
end
|
139
|
-
|
140
|
-
def subscribe_to_session_type_logging!(session_type, options, logger_proc)
|
141
|
-
SessionManager
|
142
|
-
.adaptor_class(session_type, options)
|
143
|
-
.send(
|
144
|
-
[:embedded, :embedded_db].include?(session_type.to_sym) ? :subscribe_to_transaction : :subscribe_to_request,
|
145
|
-
&logger_proc
|
146
|
-
)
|
147
|
-
end
|
148
104
|
end
|
149
105
|
end
|
data/lib/neo4j/shared.rb
CHANGED
@@ -80,7 +80,7 @@ module Neo4j::Shared
|
|
80
80
|
end
|
81
81
|
end
|
82
82
|
|
83
|
-
DATE_KEY_REGEX = /\A([^\(]+)\((\d+)([
|
83
|
+
DATE_KEY_REGEX = /\A([^\(]+)\((\d+)([ifs])\)$/
|
84
84
|
# Gives support for Rails date_select, datetime_select, time_select helpers.
|
85
85
|
def process_attributes(attributes = nil)
|
86
86
|
return attributes if attributes.blank?
|
@@ -10,8 +10,7 @@ if !defined?(Rails) && !Rake::Task.task_defined?('environment')
|
|
10
10
|
neo4j_url = ENV['NEO4J_URL'] || 'http://localhost:7474'
|
11
11
|
$LOAD_PATH.unshift File.dirname('./')
|
12
12
|
Neo4j::ActiveBase.on_establish_session do
|
13
|
-
|
14
|
-
Neo4j::SessionManager.open_neo4j_session(type, neo4j_url)
|
13
|
+
Neo4j::ActiveBase.new_driver(neo4j_url)
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
@@ -95,12 +94,14 @@ COMMENT
|
|
95
94
|
require 'neo4j/migrations/schema'
|
96
95
|
|
97
96
|
args.with_defaults(remove_missing: false)
|
97
|
+
|
98
98
|
schema_data = YAML.safe_load(File.read(SCHEMA_YAML_PATH), [Symbol])
|
99
|
+
|
99
100
|
Neo4j::Core::CypherSession::Adaptors::Base.subscribe_to_query(&method(:puts))
|
101
|
+
|
100
102
|
Neo4j::ActiveBase.run_transaction do
|
101
103
|
Neo4j::Migrations::Schema.synchronize_schema_data(Neo4j::ActiveBase.current_session, schema_data, args[:remove_missing])
|
102
|
-
|
103
|
-
Neo4j::ActiveBase.run_transaction do
|
104
|
+
|
104
105
|
runner = Neo4j::Migrations::Runner.new
|
105
106
|
runner.mark_versions_as_complete(schema_data[:versions]) # Run in test mode?
|
106
107
|
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
require 'active_support/core_ext/module/attribute_accessors_per_thread'
|
3
|
+
require 'neo4j/core/querable'
|
4
|
+
require 'neo4j/core/schema'
|
5
|
+
|
6
|
+
module Neo4j
|
7
|
+
class Transaction
|
8
|
+
include Neo4j::Core::Querable
|
9
|
+
extend Neo4j::Core::Schema
|
10
|
+
|
11
|
+
thread_mattr_accessor :stack
|
12
|
+
attr_reader :root
|
13
|
+
attr_reader :driver_tx, :driver_session
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Runs the given block in a new transaction.
|
17
|
+
# @param [Boolean] run_in_tx if true a new transaction will not be created, instead if will simply yield to the given block
|
18
|
+
# @@yield [Neo4j::Transaction::Instance]
|
19
|
+
def run(driver, run_in_tx)
|
20
|
+
return yield(nil) unless run_in_tx
|
21
|
+
|
22
|
+
tx = Neo4j::Transaction.new
|
23
|
+
yield tx
|
24
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
25
|
+
|
26
|
+
tx.mark_failed unless tx.nil?
|
27
|
+
raise e
|
28
|
+
ensure
|
29
|
+
tx.close unless tx.nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def root
|
33
|
+
stack.first
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def initialize(_options = {})
|
38
|
+
(self.stack ||= []) << self
|
39
|
+
|
40
|
+
@root = stack.first
|
41
|
+
return unless root?
|
42
|
+
@driver_session = Neo4j::Core::Driver.singleton.driver.session(Neo4j::Driver::AccessMode::WRITE)
|
43
|
+
@driver_tx = @driver_session.begin_transaction
|
44
|
+
rescue StandardError => e
|
45
|
+
self.stack = []
|
46
|
+
@driver_tx.close if @driver_tx
|
47
|
+
@driver_session.close if @driver_session
|
48
|
+
raise e
|
49
|
+
end
|
50
|
+
|
51
|
+
# Commits or marks this transaction for rollback, depending on whether #mark_failed has been previously invoked.
|
52
|
+
def close
|
53
|
+
fail 'Tried closing when transaction stack is empty (maybe you closed too many?)' if stack.empty?
|
54
|
+
fail "Closed transaction which wasn't the most recent on the stack (maybe you forgot to close one?)" if stack.pop != self
|
55
|
+
|
56
|
+
post_close! if stack.empty?
|
57
|
+
end
|
58
|
+
|
59
|
+
# Marks this transaction as failed,
|
60
|
+
# which means that it will unconditionally be rolled back
|
61
|
+
# when #close is called.
|
62
|
+
# Aliased for legacy purposes.
|
63
|
+
def mark_failed
|
64
|
+
root.mark_failed if root && root != self
|
65
|
+
@failure = true
|
66
|
+
end
|
67
|
+
|
68
|
+
alias failure mark_failed
|
69
|
+
|
70
|
+
# If it has been marked as failed.
|
71
|
+
# Aliased for legacy purposes.
|
72
|
+
def failed?
|
73
|
+
!!@failure
|
74
|
+
end
|
75
|
+
|
76
|
+
alias failure? failed?
|
77
|
+
|
78
|
+
def root?
|
79
|
+
@root == self
|
80
|
+
end
|
81
|
+
|
82
|
+
def query(*args)
|
83
|
+
options = if args[0].is_a?(::Neo4j::Core::Query)
|
84
|
+
args[1] ||= {}
|
85
|
+
else
|
86
|
+
args[1] ||= {}
|
87
|
+
args[2] ||= {}
|
88
|
+
end
|
89
|
+
options[:transaction] ||= self
|
90
|
+
|
91
|
+
self.class.query(*args)
|
92
|
+
end
|
93
|
+
|
94
|
+
def queries(options = {}, &block)
|
95
|
+
self.class.queries({ transaction: self }.merge(options), &block)
|
96
|
+
end
|
97
|
+
|
98
|
+
def after_commit_registry
|
99
|
+
@after_commit_registry ||= []
|
100
|
+
end
|
101
|
+
|
102
|
+
def after_commit(&block)
|
103
|
+
after_commit_registry << block
|
104
|
+
end
|
105
|
+
|
106
|
+
def commit
|
107
|
+
return unless root?
|
108
|
+
begin
|
109
|
+
@driver_tx.success
|
110
|
+
@driver_tx.close
|
111
|
+
ensure
|
112
|
+
@driver_session.close
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def delete
|
117
|
+
root.driver_tx.failure
|
118
|
+
root.driver_tx.close
|
119
|
+
root.driver_session.close
|
120
|
+
end
|
121
|
+
|
122
|
+
def root_tx
|
123
|
+
root.driver_tx
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def post_close!
|
129
|
+
if failed?
|
130
|
+
delete
|
131
|
+
else
|
132
|
+
commit
|
133
|
+
after_commit_registry.each(&:call)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|