activegraph 10.0.0.pre.beta.3 → 10.0.0.pre.beta.4
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 +1 -1
- data/activegraph.gemspec +2 -2
- data/lib/active_graph/base.rb +14 -32
- data/lib/active_graph/core/instrumentable.rb +3 -2
- data/lib/active_graph/core/label.rb +8 -9
- data/lib/active_graph/core/logging.rb +1 -1
- data/lib/active_graph/core/querable.rb +7 -36
- data/lib/active_graph/core/query.rb +2 -4
- data/lib/active_graph/core/query_builder.rb +1 -3
- data/lib/active_graph/core/schema.rb +0 -5
- data/lib/active_graph/core.rb +0 -1
- data/lib/active_graph/migration.rb +2 -2
- data/lib/active_graph/migrations/base.rb +2 -2
- data/lib/active_graph/migrations/helpers/id_property.rb +5 -8
- data/lib/active_graph/migrations/schema.rb +7 -7
- data/lib/active_graph/model_schema.rb +2 -2
- data/lib/active_graph/node/has_n.rb +2 -2
- data/lib/active_graph/node/persistence.rb +2 -3
- data/lib/active_graph/node/query/query_proxy.rb +1 -1
- data/lib/active_graph/node/query/query_proxy_methods.rb +2 -2
- data/lib/active_graph/node.rb +1 -0
- data/lib/active_graph/railtie.rb +3 -4
- data/lib/active_graph/relationship.rb +1 -0
- data/lib/active_graph/shared/callbacks.rb +8 -10
- data/lib/active_graph/shared/persistence.rb +5 -15
- data/lib/active_graph/shared.rb +1 -1
- data/lib/active_graph/tasks/migration.rake +8 -8
- data/lib/active_graph/transaction.rb +9 -124
- data/lib/active_graph/transactions.rb +25 -22
- data/lib/active_graph/version.rb +1 -1
- data/lib/active_graph.rb +3 -0
- metadata +6 -7
- data/lib/active_graph/core/driver.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef0444b21eb9130b0047fa423911cff404686bb29a7af0e63b66dd093d822f2b
|
4
|
+
data.tar.gz: d359a53fbe4ecfec871b596ecd3aeae4293f9369059090cec06f78e2d8a6c77c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 736e716587d1b7cb30f44263ac05108793b1819765c4e362240421022a3581b96bbbd186ca132846ade50a643f59edb422e2cb9c492c31d6c517556fb96e2c08
|
7
|
+
data.tar.gz: e985e8b8223a56a02c581f50e180851fee59b3fcbad402560f59746df6e64c3bfa8d4ccbf813571235ff5e5af1585b28939c51d835e13b8fd6b516dbe121b66c
|
data/Gemfile
CHANGED
data/activegraph.gemspec
CHANGED
@@ -38,12 +38,12 @@ DESCRIPTION
|
|
38
38
|
s.add_development_dependency('guard-rspec')
|
39
39
|
s.add_development_dependency('guard-rubocop')
|
40
40
|
s.add_development_dependency('neo4j-rake_tasks', '>= 0.3.0')
|
41
|
-
s.add_development_dependency("neo4j-#{ENV['driver'] == 'java' ? 'java' : 'ruby'}-driver", '>= 0.3.
|
41
|
+
s.add_development_dependency("neo4j-#{ENV['driver'] == 'java' ? 'java' : 'ruby'}-driver", '>= 0.3.5')
|
42
42
|
s.add_development_dependency('os')
|
43
43
|
s.add_development_dependency('pry')
|
44
44
|
s.add_development_dependency('railties', '>= 4.0')
|
45
45
|
s.add_development_dependency('rake')
|
46
|
-
s.add_development_dependency('rubocop', '
|
46
|
+
s.add_development_dependency('rubocop', '>= 0.56.0')
|
47
47
|
s.add_development_dependency('yard')
|
48
48
|
s.add_development_dependency('dryspec')
|
49
49
|
end
|
data/lib/active_graph/base.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
+
require 'active_graph/core/querable'
|
2
|
+
require 'active_graph/core/schema'
|
3
|
+
|
1
4
|
module ActiveGraph
|
2
5
|
# To contain any base login for Node/Relationship which
|
3
6
|
# is external to the main classes
|
4
7
|
module Base
|
5
8
|
include ActiveGraph::Transactions
|
9
|
+
include ActiveGraph::Core::Querable
|
10
|
+
extend ActiveGraph::Core::Schema
|
6
11
|
|
7
12
|
at_exit do
|
8
13
|
@driver&.close
|
@@ -10,16 +15,12 @@ module ActiveGraph
|
|
10
15
|
|
11
16
|
class << self
|
12
17
|
# private?
|
13
|
-
def
|
18
|
+
def driver
|
14
19
|
(@driver ||= establish_driver).tap do |driver|
|
15
20
|
fail 'No driver defined!' if driver.nil?
|
16
21
|
end
|
17
22
|
end
|
18
23
|
|
19
|
-
def driver
|
20
|
-
current_driver.driver
|
21
|
-
end
|
22
|
-
|
23
24
|
def on_establish_driver(&block)
|
24
25
|
@establish_driver_block = block
|
25
26
|
end
|
@@ -28,18 +29,10 @@ module ActiveGraph
|
|
28
29
|
@establish_driver_block.call if @establish_driver_block
|
29
30
|
end
|
30
31
|
|
31
|
-
def new_driver(url, auth_token, options = {})
|
32
|
-
verbose_query_logs = ActiveGraph::Config.fetch(:verbose_query_logs, false)
|
33
|
-
ActiveGraph::Core::Driver
|
34
|
-
.new(url, auth_token, options, verbose_query_logs: verbose_query_logs)
|
35
|
-
end
|
36
|
-
|
37
|
-
def transaction
|
38
|
-
current_transaction || Transaction
|
39
|
-
end
|
40
|
-
|
41
32
|
def query(*args)
|
42
|
-
transaction
|
33
|
+
transaction do
|
34
|
+
super(*args)
|
35
|
+
end
|
43
36
|
end
|
44
37
|
|
45
38
|
# Should support setting driver via config options
|
@@ -48,35 +41,24 @@ module ActiveGraph
|
|
48
41
|
@driver = driver
|
49
42
|
end
|
50
43
|
|
51
|
-
def
|
52
|
-
Transaction.run(current_driver, run_in_tx) do |tx|
|
53
|
-
yield tx
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def new_transaction
|
44
|
+
def validating_transaction(&block)
|
58
45
|
validate_model_schema!
|
59
|
-
|
46
|
+
transaction(&block)
|
60
47
|
end
|
61
48
|
|
62
49
|
def new_query(options = {})
|
63
50
|
validate_model_schema!
|
64
|
-
ActiveGraph::Core::Query.new(
|
51
|
+
ActiveGraph::Core::Query.new(options)
|
65
52
|
end
|
66
53
|
|
67
54
|
def magic_query(*args)
|
68
55
|
if args.empty? || args.map(&:class) == [Hash]
|
69
|
-
|
56
|
+
new_query(*args)
|
70
57
|
else
|
71
|
-
|
58
|
+
query(*args)
|
72
59
|
end
|
73
60
|
end
|
74
61
|
|
75
|
-
def current_transaction
|
76
|
-
validate_model_schema!
|
77
|
-
Transaction.root
|
78
|
-
end
|
79
|
-
|
80
62
|
def label_object(label_name)
|
81
63
|
ActiveGraph::Core::Label.new(label_name)
|
82
64
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
require 'active_support/notifications'
|
3
3
|
require 'active_graph/ansi'
|
4
|
+
require 'active_graph/core/logging'
|
4
5
|
|
5
6
|
module ActiveGraph
|
6
7
|
module Core
|
@@ -14,7 +15,7 @@ module ActiveGraph
|
|
14
15
|
def subscribe_to_request
|
15
16
|
ActiveSupport::Notifications.subscribe('neo4j.core.bolt.request') do |_, start, finish, _id, _payload|
|
16
17
|
ms = (finish - start) * 1000
|
17
|
-
yield " #{ANSI::BLUE}BOLT:#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR}
|
18
|
+
yield " #{ANSI::BLUE}BOLT:#{ANSI::CLEAR} #{ANSI::YELLOW}#{ms.round}ms#{ANSI::CLEAR}"
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
@@ -27,7 +28,7 @@ module ActiveGraph
|
|
27
28
|
source_line, line_number = Logging.first_external_path_and_line(caller_locations)
|
28
29
|
|
29
30
|
yield " #{ANSI::CYAN}#{query.context || 'CYPHER'}#{ANSI::CLEAR} #{cypher} #{params_string}" +
|
30
|
-
("\n ↳ #{source_line}:#{line_number}" if
|
31
|
+
("\n ↳ #{source_line}:#{line_number}" if ActiveGraph::Config.fetch(:verbose_query_logs, false) && source_line).to_s
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
@@ -76,7 +76,7 @@ module ActiveGraph
|
|
76
76
|
end
|
77
77
|
|
78
78
|
def constraints(_options = {})
|
79
|
-
ActiveGraph::
|
79
|
+
ActiveGraph::Base.constraints.select do |definition|
|
80
80
|
definition[:label] == @name.to_sym
|
81
81
|
end
|
82
82
|
end
|
@@ -109,13 +109,13 @@ module ActiveGraph
|
|
109
109
|
|
110
110
|
class << self
|
111
111
|
def indexes
|
112
|
-
ActiveGraph::
|
112
|
+
ActiveGraph::Base.indexes
|
113
113
|
end
|
114
114
|
|
115
115
|
def drop_indexes
|
116
116
|
indexes.each do |definition|
|
117
117
|
begin
|
118
|
-
ActiveGraph::
|
118
|
+
ActiveGraph::Base.query("DROP INDEX ON :`#{definition[:label]}`(#{definition[:properties][0]})")
|
119
119
|
rescue Neo4j::Driver::Exceptions::DatabaseException
|
120
120
|
# This will error on each constraint. Ignore and continue.
|
121
121
|
next
|
@@ -124,11 +124,10 @@ module ActiveGraph
|
|
124
124
|
end
|
125
125
|
|
126
126
|
def drop_constraints
|
127
|
-
ActiveGraph::
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
ActiveGraph::Transaction.query("DROP CONSTRAINT ON (n:`#{definition[:label]}`) ASSERT n.`#{definition[:properties][0]}` IS UNIQUE")
|
127
|
+
ActiveGraph::Base.transaction do |tx|
|
128
|
+
tx.run('CALL db.constraints').each do |record|
|
129
|
+
tx.run("DROP #{record.keys.include?(:name) ? "CONSTRAINT #{record[:name]}" : record[:description]}")
|
130
|
+
end
|
132
131
|
end
|
133
132
|
end
|
134
133
|
|
@@ -147,7 +146,7 @@ module ActiveGraph
|
|
147
146
|
end
|
148
147
|
|
149
148
|
def schema_query(cypher)
|
150
|
-
ActiveGraph::
|
149
|
+
ActiveGraph::Base.query(cypher, {})
|
151
150
|
end
|
152
151
|
|
153
152
|
def validate_index_options!(options)
|
@@ -30,7 +30,7 @@ module ActiveGraph
|
|
30
30
|
def neo4j_gem_path
|
31
31
|
return if !defined?(::Rails.root)
|
32
32
|
|
33
|
-
@neo4j_gem_path ||= File.expand_path('../../..', ActiveGraph::Base.method(:
|
33
|
+
@neo4j_gem_path ||= File.expand_path('../../..', ActiveGraph::Base.method(:driver).source_location[0])
|
34
34
|
end
|
35
35
|
|
36
36
|
def active_support_gem_path
|
@@ -27,29 +27,8 @@ module ActiveGraph
|
|
27
27
|
|
28
28
|
query_builder.instance_eval(&block)
|
29
29
|
|
30
|
-
|
31
|
-
query_set(
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# If called without a block, returns a Transaction object
|
36
|
-
# which can be used to call query/queries/mark_failed/commit
|
37
|
-
# If called with a block, the Transaction object is yielded
|
38
|
-
# to the block and `commit` is ensured. Any uncaught exceptions
|
39
|
-
# will mark the transaction as failed first
|
40
|
-
def transaction
|
41
|
-
return Transaction.new unless block_given?
|
42
|
-
|
43
|
-
begin
|
44
|
-
tx = transaction
|
45
|
-
|
46
|
-
yield tx
|
47
|
-
rescue => e
|
48
|
-
tx.mark_failed if tx
|
49
|
-
|
50
|
-
raise e
|
51
|
-
ensure
|
52
|
-
tx.close if tx
|
30
|
+
transaction do
|
31
|
+
query_set(query_builder.queries, options)
|
53
32
|
end
|
54
33
|
end
|
55
34
|
|
@@ -60,28 +39,20 @@ module ActiveGraph
|
|
60
39
|
end
|
61
40
|
end
|
62
41
|
|
63
|
-
def query_set(
|
42
|
+
def query_set(queries, options = {})
|
64
43
|
setup_queries!(queries, skip_instrumentation: options[:skip_instrumentation])
|
65
44
|
|
66
45
|
ActiveSupport::Notifications.instrument('neo4j.core.bolt.request') do
|
67
46
|
self.wrap_level = options[:wrap_level]
|
68
|
-
|
69
|
-
|
47
|
+
transaction do |tx|
|
48
|
+
queries.map do |query|
|
49
|
+
result_from_data(tx.run(query.cypher, query.parameters))
|
50
|
+
end
|
70
51
|
end
|
71
52
|
rescue Neo4j::Driver::Exceptions::Neo4jException => e
|
72
53
|
raise ActiveGraph::Core::CypherError.new_from(e.code, e.message) # , e.stack_track.to_a
|
73
54
|
end
|
74
55
|
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
def new_or_current_transaction(tx, &block)
|
79
|
-
if tx
|
80
|
-
yield(tx)
|
81
|
-
else
|
82
|
-
transaction(&block)
|
83
|
-
end
|
84
|
-
end
|
85
56
|
end
|
86
57
|
end
|
87
58
|
end
|
@@ -68,8 +68,6 @@ module ActiveGraph
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def initialize(options = {})
|
71
|
-
@driver = options[:driver]
|
72
|
-
|
73
71
|
@options = options
|
74
72
|
@clauses = []
|
75
73
|
@_params = {}
|
@@ -237,7 +235,7 @@ module ActiveGraph
|
|
237
235
|
def response
|
238
236
|
return @response if @response
|
239
237
|
|
240
|
-
@response = ActiveGraph::
|
238
|
+
@response = ActiveGraph::Base.query(self, wrap_level: (:core_entity if unwrapped?))
|
241
239
|
end
|
242
240
|
|
243
241
|
def raise_if_cypher_error!(response)
|
@@ -374,7 +372,7 @@ module ActiveGraph
|
|
374
372
|
end
|
375
373
|
|
376
374
|
def &(other)
|
377
|
-
self.class.new
|
375
|
+
self.class.new.tap do |new_query|
|
378
376
|
new_query.options = options.merge(other.options)
|
379
377
|
new_query.clauses = clauses + other.clauses
|
380
378
|
end.params(other._params)
|
data/lib/active_graph/core.rb
CHANGED
@@ -28,7 +28,7 @@ module ActiveGraph
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def query(*args)
|
31
|
-
ActiveGraph::Base.
|
31
|
+
ActiveGraph::Base.query(*args)
|
32
32
|
end
|
33
33
|
|
34
34
|
class AddIdProperty < ActiveGraph::Migration
|
@@ -115,7 +115,7 @@ MESSAGE
|
|
115
115
|
# def id_batch_set(label, id_property, new_ids, count)
|
116
116
|
# tx = ActiveGraph::Base.new_transaction
|
117
117
|
|
118
|
-
# ActiveGraph::Base.
|
118
|
+
# ActiveGraph::Base.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]]|
|
@@ -63,11 +63,11 @@ module ActiveGraph
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def migration_transaction(&block)
|
66
|
-
ActiveGraph::Base.
|
66
|
+
transactions? ? ActiveGraph::Base.transaction(&block) : block.call
|
67
67
|
end
|
68
68
|
|
69
69
|
def log_queries
|
70
|
-
subscriber = ActiveGraph::
|
70
|
+
subscriber = ActiveGraph::Base.subscribe_to_query(&method(:output))
|
71
71
|
yield
|
72
72
|
ensure
|
73
73
|
ActiveSupport::Notifications.unsubscribe(subscriber) if subscriber
|
@@ -27,23 +27,20 @@ module ActiveGraph
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def id_batch_set(label, id_property, new_ids, count)
|
30
|
-
|
31
|
-
|
32
|
-
execute("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
|
30
|
+
ActiveGraph::Base.transaction do
|
31
|
+
execute("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
|
33
32
|
with COLLECT(n) as nodes, #{new_ids} as ids
|
34
33
|
FOREACH(i in range(0,#{count - 1})|
|
35
34
|
FOREACH(node in [nodes[i]]|
|
36
35
|
SET node.#{id_property} = ids[i]))
|
37
36
|
RETURN distinct(true)
|
38
37
|
LIMIT #{count}")
|
39
|
-
|
40
|
-
|
41
|
-
rescue ActiveGraph::Server::CypherResponse::ResponseError
|
38
|
+
count
|
39
|
+
end
|
40
|
+
rescue ActiveGraph::Server::CypherResponse::ResponseError
|
42
41
|
new_max_per_batch = (max_per_batch * 0.8).round
|
43
42
|
output "Error querying #{max_per_batch} nodes. Trying #{new_max_per_batch}"
|
44
43
|
new_max_per_batch
|
45
|
-
ensure
|
46
|
-
tx.close
|
47
44
|
end
|
48
45
|
|
49
46
|
def print_status(last_time_taken, max_per_batch, nodes_left)
|
@@ -2,16 +2,16 @@ module ActiveGraph
|
|
2
2
|
module Migrations
|
3
3
|
module Schema
|
4
4
|
class << self
|
5
|
-
def fetch_schema_data
|
6
|
-
{constraints: fetch_constraint_descriptions
|
7
|
-
indexes: fetch_index_descriptions
|
5
|
+
def fetch_schema_data
|
6
|
+
{constraints: fetch_constraint_descriptions.sort,
|
7
|
+
indexes: fetch_index_descriptions.sort}
|
8
8
|
end
|
9
9
|
|
10
|
-
def synchronize_schema_data(
|
10
|
+
def synchronize_schema_data(schema_data, remove_missing)
|
11
11
|
queries = []
|
12
12
|
queries += drop_and_create_queries(fetch_constraint_descriptions(driver), schema_data[:constraints], remove_missing)
|
13
13
|
queries += drop_and_create_queries(fetch_index_descriptions(driver), schema_data[:indexes], remove_missing)
|
14
|
-
|
14
|
+
ActiveGraph::Base.queries do
|
15
15
|
queries.each { |query| append query }
|
16
16
|
end
|
17
17
|
end
|
@@ -19,11 +19,11 @@ module ActiveGraph
|
|
19
19
|
private
|
20
20
|
|
21
21
|
def fetch_constraint_descriptions(driver)
|
22
|
-
|
22
|
+
ActiveGraph::Base.query('CALL db.constraints()').map(&:description)
|
23
23
|
end
|
24
24
|
|
25
25
|
def fetch_index_descriptions(driver)
|
26
|
-
result =
|
26
|
+
result = ActiveGraph::Base.query('CALL db.indexes()')
|
27
27
|
if result.columns.include?(:description)
|
28
28
|
v3_indexes(result)
|
29
29
|
else
|
@@ -32,7 +32,7 @@ module ActiveGraph
|
|
32
32
|
def model_constraints
|
33
33
|
return @model_constraints if @model_constraints
|
34
34
|
|
35
|
-
constraints = ActiveGraph::
|
35
|
+
constraints = ActiveGraph::Base.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 ActiveGraph
|
|
43
43
|
def model_indexes
|
44
44
|
return @model_indexes if @model_indexes
|
45
45
|
|
46
|
-
indexes = ActiveGraph::
|
46
|
+
indexes = ActiveGraph::Base.indexes.each_with_object({}) do |row, result|
|
47
47
|
result[row[:label]] ||= []
|
48
48
|
result[row[:label]] << row[:properties]
|
49
49
|
end
|
@@ -446,7 +446,7 @@ module ActiveGraph::Node
|
|
446
446
|
|
447
447
|
clear_deferred_nodes_for_association(name)
|
448
448
|
|
449
|
-
|
449
|
+
ActiveGraph::Base.transaction { association_proxy(name).replace_with(other_nodes) }
|
450
450
|
end
|
451
451
|
end
|
452
452
|
|
@@ -524,7 +524,7 @@ module ActiveGraph::Node
|
|
524
524
|
if persisted?
|
525
525
|
other_node.save if other_node.respond_to?(:persisted?) && !other_node.persisted?
|
526
526
|
association_proxy_cache.clear # TODO: Should probably just clear for this association...
|
527
|
-
|
527
|
+
ActiveGraph::Base.transaction { association_proxy(name).replace_with(other_node) }
|
528
528
|
# handle_non_persisted_node(other_node)
|
529
529
|
else
|
530
530
|
defer_create(name, other_node, clear: true)
|
@@ -93,10 +93,9 @@ module ActiveGraph::Node
|
|
93
93
|
end
|
94
94
|
|
95
95
|
# The pending associations are cleared during the save process, so it's necessary to
|
96
|
-
# build the processable hash before it begins.
|
97
|
-
# need to be created after the node is saved, a new transaction is started.
|
96
|
+
# build the processable hash before it begins.
|
98
97
|
def cascade_save
|
99
|
-
|
98
|
+
ActiveGraph::Base.transaction do
|
100
99
|
yield.tap { process_unpersisted_nodes! }
|
101
100
|
end
|
102
101
|
end
|
@@ -205,7 +205,7 @@ module ActiveGraph
|
|
205
205
|
fail 'Can only create relationships on associations' if !@association
|
206
206
|
other_nodes = _nodeify!(*other_nodes)
|
207
207
|
|
208
|
-
ActiveGraph::Base.
|
208
|
+
ActiveGraph::Base.transaction do
|
209
209
|
other_nodes.each do |other_node|
|
210
210
|
if other_node.neo_id
|
211
211
|
other_node.try(:delete_reverse_has_one_core_rel, association)
|
@@ -152,10 +152,10 @@ module ActiveGraph
|
|
152
152
|
fail 'Method invalid when called on Class objects' unless source_object
|
153
153
|
result = self.where(params).first
|
154
154
|
return result unless result.nil?
|
155
|
-
ActiveGraph::Base.
|
155
|
+
ActiveGraph::Base.transaction do
|
156
156
|
node = model.create(params)
|
157
157
|
self << node
|
158
|
-
|
158
|
+
node
|
159
159
|
end
|
160
160
|
end
|
161
161
|
|
data/lib/active_graph/node.rb
CHANGED
@@ -46,6 +46,7 @@ module ActiveGraph
|
|
46
46
|
include ActiveGraph::Node::Enum
|
47
47
|
include ActiveGraph::Shared::PermittedAttributes
|
48
48
|
include ActiveGraph::Node::DependentCallbacks
|
49
|
+
include ActiveGraph::Transactions
|
49
50
|
|
50
51
|
def initialize(args = nil)
|
51
52
|
self.class.ensure_id_property_info! # So that we make sure all objects have an id_property
|
data/lib/active_graph/railtie.rb
CHANGED
@@ -2,7 +2,6 @@ require 'active_support/notifications'
|
|
2
2
|
require 'rails/railtie'
|
3
3
|
# Need the action_dispatch railtie to have action_dispatch.rescue_responses initialized correctly
|
4
4
|
require 'action_dispatch/railtie'
|
5
|
-
require 'active_graph/core/driver'
|
6
5
|
|
7
6
|
module ActiveGraph
|
8
7
|
class Railtie < ::Rails::Railtie
|
@@ -65,7 +64,7 @@ module ActiveGraph
|
|
65
64
|
auth_token ||= username ? Neo4j::Driver::AuthTokens.basic(username, password) : Neo4j::Driver::AuthTokens.none
|
66
65
|
register_neo4j_cypher_logging
|
67
66
|
|
68
|
-
|
67
|
+
Neo4j::Driver::GraphDatabase.driver(url || path || default_driver_path_or_url, auth_token, config)
|
69
68
|
end
|
70
69
|
|
71
70
|
def final_driver_config!(neo4j_config)
|
@@ -99,8 +98,8 @@ module ActiveGraph
|
|
99
98
|
logger_proc = ->(message) do
|
100
99
|
(ActiveGraph::Config[:logger] ||= Rails.logger).debug message
|
101
100
|
end
|
102
|
-
ActiveGraph::
|
103
|
-
ActiveGraph::
|
101
|
+
ActiveGraph::Base.subscribe_to_query(&logger_proc)
|
102
|
+
ActiveGraph::Base.subscribe_to_request(&logger_proc)
|
104
103
|
|
105
104
|
@neo4j_cypher_logging_registered = true
|
106
105
|
end
|
@@ -20,16 +20,14 @@ module ActiveGraph
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def destroy #:nodoc:
|
23
|
-
|
24
|
-
|
25
|
-
|
23
|
+
ActiveGraph::Base.validating_transaction do |tx|
|
24
|
+
tx.after_commit { run_callbacks(:destroy_commit) {} }
|
25
|
+
run_callbacks(:destroy) { super }
|
26
|
+
end
|
26
27
|
rescue
|
27
28
|
@_deleted = false
|
28
29
|
@attributes = @attributes.dup
|
29
|
-
tx.mark_failed if tx
|
30
30
|
raise
|
31
|
-
ensure
|
32
|
-
tx.close if tx
|
33
31
|
end
|
34
32
|
|
35
33
|
def touch #:nodoc:
|
@@ -51,15 +49,15 @@ module ActiveGraph
|
|
51
49
|
end
|
52
50
|
|
53
51
|
def create_model #:nodoc:
|
54
|
-
|
55
|
-
tx.
|
52
|
+
ActiveGraph::Base.transaction do |tx|
|
53
|
+
tx.after_commit { run_callbacks(:create_commit) {} }
|
56
54
|
run_callbacks(:create) { super }
|
57
55
|
end
|
58
56
|
end
|
59
57
|
|
60
58
|
def update_model(*) #:nodoc:
|
61
|
-
|
62
|
-
tx.
|
59
|
+
ActiveGraph::Base.transaction do |tx|
|
60
|
+
tx.after_commit { run_callbacks(:update_commit) {} }
|
63
61
|
run_callbacks(:update) { super }
|
64
62
|
end
|
65
63
|
end
|
@@ -89,14 +89,10 @@ module ActiveGraph::Shared
|
|
89
89
|
@_create_or_updating = true
|
90
90
|
apply_default_values
|
91
91
|
result = _persisted_obj ? update_model : create_model
|
92
|
-
current_transaction = ActiveGraph::Base.current_transaction
|
93
92
|
|
94
|
-
|
93
|
+
ActiveGraph::Base.transaction(&:failure) if result == false
|
95
94
|
|
96
95
|
result != false
|
97
|
-
rescue => e
|
98
|
-
current_transaction.mark_failed if current_transaction
|
99
|
-
raise e
|
100
96
|
ensure
|
101
97
|
@_create_or_updating = nil
|
102
98
|
end
|
@@ -180,10 +176,10 @@ module ActiveGraph::Shared
|
|
180
176
|
# Updates this resource with all the attributes from the passed-in Hash and requests that the record be saved.
|
181
177
|
# If saving fails because the resource is invalid then false will be returned.
|
182
178
|
def update(attributes)
|
183
|
-
|
179
|
+
ActiveGraph::Base.transaction do |tx|
|
184
180
|
self.attributes = process_attributes(attributes)
|
185
181
|
saved = save
|
186
|
-
tx.
|
182
|
+
tx.failure unless saved
|
187
183
|
saved
|
188
184
|
end
|
189
185
|
end
|
@@ -197,7 +193,7 @@ module ActiveGraph::Shared
|
|
197
193
|
|
198
194
|
def update_db_properties(hash)
|
199
195
|
fail ::ActiveGraph::Error, 'can not update on a new record object' unless persisted?
|
200
|
-
|
196
|
+
ActiveGraph::Base.transaction do
|
201
197
|
db_values = props_for_db(hash)
|
202
198
|
neo4j_query(query_as(:n).set(n: db_values))
|
203
199
|
db_values.each_pair { |k, v| self.public_send(:"#{k}=", v) }
|
@@ -210,7 +206,7 @@ module ActiveGraph::Shared
|
|
210
206
|
|
211
207
|
# Same as {#update_attributes}, but raises an exception if saving fails.
|
212
208
|
def update!(attributes)
|
213
|
-
|
209
|
+
ActiveGraph::Base.transaction do
|
214
210
|
self.attributes = process_attributes(attributes)
|
215
211
|
save!
|
216
212
|
end
|
@@ -227,12 +223,6 @@ module ActiveGraph::Shared
|
|
227
223
|
end
|
228
224
|
end
|
229
225
|
|
230
|
-
module ClassMethods
|
231
|
-
def run_transaction(run_in_tx = true)
|
232
|
-
ActiveGraph::Base.run_transaction(run_in_tx) { |tx| yield tx }
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
226
|
protected
|
237
227
|
|
238
228
|
def increment_by_query!(match_query, attribute, by, element_name = :n)
|
data/lib/active_graph/shared.rb
CHANGED
@@ -9,8 +9,8 @@ if !defined?(Rails) && !Rake::Task.task_defined?('environment')
|
|
9
9
|
require 'ostruct'
|
10
10
|
neo4j_url = ENV['NEO4J_URL'] || 'http://localhost:7474'
|
11
11
|
$LOAD_PATH.unshift File.dirname('./')
|
12
|
-
ActiveGraph::Base.
|
13
|
-
|
12
|
+
ActiveGraph::Base.on_establish_driver do
|
13
|
+
Neo4j::Driver::GraphDatabase.driver(neo4j_url)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
@@ -64,7 +64,7 @@ namespace :neo4j do
|
|
64
64
|
COMMENT
|
65
65
|
|
66
66
|
def check_neo4j_version_3
|
67
|
-
if ActiveGraph::Base.
|
67
|
+
if ActiveGraph::Base.version > '3.0.0'
|
68
68
|
yield
|
69
69
|
else
|
70
70
|
puts 'WARNING: This task does not work for versions of Neo4j before 3.0.0'
|
@@ -76,7 +76,7 @@ COMMENT
|
|
76
76
|
check_neo4j_version_3 do
|
77
77
|
require 'active_graph/migrations/schema'
|
78
78
|
|
79
|
-
schema_data = ActiveGraph::Migrations::Schema.fetch_schema_data
|
79
|
+
schema_data = ActiveGraph::Migrations::Schema.fetch_schema_data
|
80
80
|
|
81
81
|
runner = ActiveGraph::Migrations::Runner.new
|
82
82
|
schema_data[:versions] = runner.complete_migration_versions.sort
|
@@ -97,13 +97,13 @@ COMMENT
|
|
97
97
|
|
98
98
|
schema_data = YAML.safe_load(File.read(SCHEMA_YAML_PATH), [Symbol])
|
99
99
|
|
100
|
-
ActiveGraph::
|
100
|
+
ActiveGraph::Base.subscribe_to_query(&method(:puts))
|
101
101
|
|
102
|
-
ActiveGraph::Base.
|
103
|
-
ActiveGraph::Migrations::Schema.synchronize_schema_data(
|
102
|
+
ActiveGraph::Base.transaction do
|
103
|
+
ActiveGraph::Migrations::Schema.synchronize_schema_data(schema_data, args[:remove_missing])
|
104
104
|
end
|
105
105
|
|
106
|
-
ActiveGraph::Base.
|
106
|
+
ActiveGraph::Base.transaction do
|
107
107
|
runner = ActiveGraph::Migrations::Runner.new
|
108
108
|
runner.mark_versions_as_complete(schema_data[:versions]) # Run in test mode?
|
109
109
|
end
|
@@ -1,139 +1,24 @@
|
|
1
|
-
require 'active_support/core_ext/module/delegation'
|
2
|
-
require 'active_support/core_ext/module/attribute_accessors_per_thread'
|
3
|
-
require 'active_graph/core/querable'
|
4
|
-
require 'active_graph/core/schema'
|
5
|
-
|
6
1
|
module ActiveGraph
|
7
|
-
|
8
|
-
|
9
|
-
|
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 [ActiveGraph::Transaction::Instance]
|
19
|
-
def run(_driver, run_in_tx)
|
20
|
-
return yield(nil) unless run_in_tx
|
21
|
-
|
22
|
-
tx = ActiveGraph::Transaction.new
|
23
|
-
yield tx
|
24
|
-
rescue Exception => e # rubocop:disable Lint/RescueException
|
25
|
-
tx.mark_failed unless tx.nil?
|
26
|
-
raise e
|
27
|
-
ensure
|
28
|
-
tx.close unless tx.nil?
|
29
|
-
end
|
30
|
-
|
31
|
-
def root
|
32
|
-
initialized_stack.first
|
33
|
-
end
|
34
|
-
|
35
|
-
def initialized_stack
|
36
|
-
self.stack ||= []
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def initialize(_options = {})
|
41
|
-
self.class.initialized_stack << self
|
42
|
-
@root = stack.first
|
43
|
-
return unless root?
|
44
|
-
@driver_session = Base.current_driver.driver.session(Neo4j::Driver::AccessMode::WRITE)
|
45
|
-
@driver_tx = @driver_session.begin_transaction
|
46
|
-
rescue StandardError => e
|
47
|
-
self.stack = []
|
48
|
-
@driver_tx.close if @driver_tx
|
49
|
-
@driver_session.close if @driver_session
|
50
|
-
raise e
|
51
|
-
end
|
52
|
-
|
53
|
-
# Commits or marks this transaction for rollback, depending on whether #mark_failed has been previously invoked.
|
54
|
-
def close
|
55
|
-
fail 'Tried closing when transaction stack is empty (maybe you closed too many?)' if stack.empty?
|
56
|
-
fail "Closed transaction which wasn't the most recent on the stack (maybe you forgot to close one?)" if stack.pop != self
|
57
|
-
|
58
|
-
post_close! if stack.empty?
|
59
|
-
end
|
60
|
-
|
61
|
-
# Marks this transaction as failed,
|
62
|
-
# which means that it will unconditionally be rolled back
|
63
|
-
# when #close is called.
|
64
|
-
# Aliased for legacy purposes.
|
65
|
-
def mark_failed
|
66
|
-
root.mark_failed if root && root != self
|
2
|
+
module Transaction
|
3
|
+
def failure
|
4
|
+
super
|
67
5
|
@failure = true
|
68
6
|
end
|
69
7
|
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
def failed?
|
75
|
-
!!@failure
|
76
|
-
end
|
77
|
-
|
78
|
-
alias failure? failed?
|
79
|
-
|
80
|
-
def root?
|
81
|
-
@root == self
|
82
|
-
end
|
83
|
-
|
84
|
-
def query(*args)
|
85
|
-
options = if args[0].is_a?(::ActiveGraph::Core::Query)
|
86
|
-
args[1] ||= {}
|
87
|
-
else
|
88
|
-
args[1] ||= {}
|
89
|
-
args[2] ||= {}
|
90
|
-
end
|
91
|
-
options[:transaction] ||= self
|
92
|
-
|
93
|
-
self.class.query(*args)
|
94
|
-
end
|
95
|
-
|
96
|
-
def queries(options = {}, &block)
|
97
|
-
self.class.queries({ transaction: self }.merge(options), &block)
|
98
|
-
end
|
99
|
-
|
100
|
-
def after_commit_registry
|
101
|
-
@after_commit_registry ||= []
|
8
|
+
def close
|
9
|
+
success
|
10
|
+
super
|
11
|
+
after_commit_registry.each(&:call) unless @failure
|
102
12
|
end
|
103
13
|
|
104
14
|
def after_commit(&block)
|
105
15
|
after_commit_registry << block
|
106
16
|
end
|
107
17
|
|
108
|
-
def commit
|
109
|
-
return unless root?
|
110
|
-
begin
|
111
|
-
@driver_tx.success
|
112
|
-
@driver_tx.close
|
113
|
-
ensure
|
114
|
-
@driver_session.close
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
def delete
|
119
|
-
root.driver_tx.failure
|
120
|
-
root.driver_tx.close
|
121
|
-
root.driver_session.close
|
122
|
-
end
|
123
|
-
|
124
|
-
def root_tx
|
125
|
-
root.driver_tx
|
126
|
-
end
|
127
|
-
|
128
18
|
private
|
129
19
|
|
130
|
-
def
|
131
|
-
|
132
|
-
delete
|
133
|
-
else
|
134
|
-
commit
|
135
|
-
after_commit_registry.each(&:call)
|
136
|
-
end
|
20
|
+
def after_commit_registry
|
21
|
+
@after_commit_registry ||= []
|
137
22
|
end
|
138
23
|
end
|
139
24
|
end
|
@@ -5,50 +5,53 @@ module ActiveGraph
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
included do
|
8
|
-
thread_mattr_accessor :
|
8
|
+
thread_mattr_accessor :explicit_session, :tx
|
9
9
|
end
|
10
10
|
|
11
11
|
class_methods do
|
12
12
|
def session(*args)
|
13
|
-
driver.session(*args) do |session|
|
14
|
-
self.
|
13
|
+
ActiveGraph::Base.driver.session(*args) do |session|
|
14
|
+
self.explicit_session = session
|
15
15
|
yield session
|
16
16
|
session.last_bookmark
|
17
|
-
ensure
|
18
|
-
self.ag_session = nil
|
19
17
|
end
|
20
18
|
end
|
21
19
|
|
22
|
-
def
|
23
|
-
send_transaction(:
|
20
|
+
def transaction(**config, &block)
|
21
|
+
send_transaction(:begin_transaction, **config, &block)
|
24
22
|
end
|
25
|
-
alias transaction write_transaction
|
26
23
|
|
27
|
-
def
|
28
|
-
send_transaction(:
|
24
|
+
def write_transaction(**config, &block)
|
25
|
+
send_transaction(:write_transaction, **config, &block)
|
29
26
|
end
|
30
27
|
|
31
|
-
def
|
32
|
-
send_transaction(:
|
28
|
+
def read_transaction(**config, &block)
|
29
|
+
send_transaction(:read_transaction, **config, &block)
|
33
30
|
end
|
34
31
|
|
35
32
|
private
|
36
33
|
|
37
|
-
def send_transaction(method, config
|
38
|
-
return
|
39
|
-
return
|
40
|
-
driver.session
|
34
|
+
def send_transaction(method, **config, &block)
|
35
|
+
return checked_yield(tx, &block) if tx&.open?
|
36
|
+
return run_transaction_work(explicit_session, method, **config, &block) if explicit_session&.open?
|
37
|
+
driver.session do |session|
|
38
|
+
run_transaction_work(session, method, **config, &block)
|
39
|
+
end
|
41
40
|
end
|
42
41
|
|
43
|
-
def
|
44
|
-
session.send(method, config) do |tx|
|
42
|
+
def run_transaction_work(session, method, **config, &block)
|
43
|
+
session.send(method, **config) do |tx|
|
45
44
|
self.tx = tx
|
46
|
-
|
47
|
-
tx.success
|
48
|
-
ensure
|
49
|
-
self.tx = nil
|
45
|
+
checked_yield(tx, &block)
|
50
46
|
end
|
51
47
|
end
|
48
|
+
|
49
|
+
def checked_yield(tx)
|
50
|
+
yield tx
|
51
|
+
rescue StandardError => e
|
52
|
+
tx.failure
|
53
|
+
raise e
|
54
|
+
end
|
52
55
|
end
|
53
56
|
end
|
54
57
|
end
|
data/lib/active_graph/version.rb
CHANGED
data/lib/active_graph.rb
CHANGED
@@ -4,6 +4,7 @@ require 'active_graph/version'
|
|
4
4
|
require 'active_graph/core'
|
5
5
|
require 'active_graph/core/query_ext' # From this gem
|
6
6
|
|
7
|
+
require 'active_support/core_ext/module/attribute_accessors_per_thread'
|
7
8
|
require 'active_graph/transactions'
|
8
9
|
require 'active_graph/base'
|
9
10
|
require 'active_graph/model_schema'
|
@@ -118,3 +119,5 @@ if defined?(Rails)
|
|
118
119
|
require 'rails/generators'
|
119
120
|
require 'rails/generators/neo4j_generator'
|
120
121
|
end
|
122
|
+
|
123
|
+
Neo4j::Driver::Transaction.prepend ActiveGraph::Transaction
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activegraph
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.0.0.pre.beta.
|
4
|
+
version: 10.0.0.pre.beta.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Ronge, Brian Underwood, Chris Grigg, Heinrich Klobuczek
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - ">="
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.3.
|
131
|
+
version: 0.3.5
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.3.
|
138
|
+
version: 0.3.5
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: os
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -196,14 +196,14 @@ dependencies:
|
|
196
196
|
name: rubocop
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
198
198
|
requirements:
|
199
|
-
- - "
|
199
|
+
- - ">="
|
200
200
|
- !ruby/object:Gem::Version
|
201
201
|
version: 0.56.0
|
202
202
|
type: :development
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
|
-
- - "
|
206
|
+
- - ">="
|
207
207
|
- !ruby/object:Gem::Version
|
208
208
|
version: 0.56.0
|
209
209
|
- !ruby/object:Gem::Dependency
|
@@ -262,7 +262,6 @@ files:
|
|
262
262
|
- lib/active_graph/core.rb
|
263
263
|
- lib/active_graph/core/connection_failed_error.rb
|
264
264
|
- lib/active_graph/core/cypher_error.rb
|
265
|
-
- lib/active_graph/core/driver.rb
|
266
265
|
- lib/active_graph/core/instrumentable.rb
|
267
266
|
- lib/active_graph/core/label.rb
|
268
267
|
- lib/active_graph/core/logging.rb
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/module/attribute_accessors'
|
2
|
-
require 'active_graph/core/logging'
|
3
|
-
require 'active_graph/version'
|
4
|
-
|
5
|
-
module ActiveGraph
|
6
|
-
module Core
|
7
|
-
class Driver
|
8
|
-
USER_AGENT_STRING = "activegraph-gem/#{::ActiveGraph::VERSION} (https://github.com/neo4jrb/activegraph)"
|
9
|
-
|
10
|
-
attr_accessor :wrap_level
|
11
|
-
attr_reader :options, :driver, :url
|
12
|
-
delegate :close, to: :driver
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def new_instance(url, auth_token, options = {})
|
16
|
-
Neo4j::Driver::GraphDatabase.driver(url, auth_token, options)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def initialize(url, auth_token = Neo4j::Driver::AuthTokens.none, options = {}, extended_options = {})
|
21
|
-
@url = url
|
22
|
-
@driver = self.class.new_instance(url, auth_token, options)
|
23
|
-
@options = extended_options
|
24
|
-
end
|
25
|
-
|
26
|
-
def logger
|
27
|
-
return @logger if @logger
|
28
|
-
|
29
|
-
@logger = if @options[:logger]
|
30
|
-
@options[:logger]
|
31
|
-
else
|
32
|
-
Logger.new(logger_location).tap do |logger|
|
33
|
-
logger.level = logger_level
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def logger_location
|
41
|
-
@options[:logger_location] || STDOUT
|
42
|
-
end
|
43
|
-
|
44
|
-
def logger_level
|
45
|
-
@options[:logger_level] || Logger::WARN
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|