neo4j 9.6.2 → 10.0.0.pre.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|