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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bf12b2e24dd9557ad7d5a232f653e150241910a48293d4aeba5f5e16f160a42
4
- data.tar.gz: 36adc4653772d9132ea19f086b361f4d14fe61704ad1c75214ff441bac0652c9
3
+ metadata.gz: ef0444b21eb9130b0047fa423911cff404686bb29a7af0e63b66dd093d822f2b
4
+ data.tar.gz: d359a53fbe4ecfec871b596ecd3aeae4293f9369059090cec06f78e2d8a6c77c
5
5
  SHA512:
6
- metadata.gz: e0b15269740380e2bf9bf274f0d3cf89c0bc1394d3469c92919ce0fa172a0b7b22abeec2f7484440c2ff1dd38be275fbb6307aebcf1f8b5174cca8a8568aab70
7
- data.tar.gz: fa92fc22ff87ae268a8ef951adb7dc2b838d3673db36ec34cbbf204be1584814a1c48d9c97fa2b87ae8ea09261ffb0a7a72e4c8be2f7dd4ac081c730b3be3b53
6
+ metadata.gz: 736e716587d1b7cb30f44263ac05108793b1819765c4e362240421022a3581b96bbbd186ca132846ade50a643f59edb422e2cb9c492c31d6c517556fb96e2c08
7
+ data.tar.gz: e985e8b8223a56a02c581f50e180851fee59b3fcbad402560f59746df6e64c3bfa8d4ccbf813571235ff5e5af1585b28939c51d835e13b8fd6b516dbe121b66c
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source 'http://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- # gem 'neo4j-ruby-driver', path: '../neo4j-ruby-driver'
5
+ #gem "neo4j-#{ENV['driver'] == 'java' ? 'java' : 'ruby'}-driver", path: '../neo4j-ruby-driver'
6
6
 
7
7
  gem 'listen', '< 3.1'
8
8
 
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.0')
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', '~> 0.56.0')
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
@@ -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 current_driver
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.query(*args)
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 run_transaction(run_in_tx = true)
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
- ActiveGraph::Transaction.new
46
+ transaction(&block)
60
47
  end
61
48
 
62
49
  def new_query(options = {})
63
50
  validate_model_schema!
64
- ActiveGraph::Core::Query.new({driver: current_driver}.merge(options))
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
- Base.new_query(*args)
56
+ new_query(*args)
70
57
  else
71
- Base.current_driver.query(*args)
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} #{Base.current_driver.url}"
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 Base.current_driver.options[:verbose_query_logs] && source_line).to_s
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::Transaction.constraints.select do |definition|
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::Transaction.indexes
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::Transaction.query("DROP INDEX ON :`#{definition[:label]}`(#{definition[:properties][0]})")
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::Transaction.named_constraints.each do |constraint|
128
- ActiveGraph::Transaction.query("DROP CONSTRAINT #{constraint.name}")
129
- end
130
- ActiveGraph::Transaction.constraints.each do |definition|
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::Transaction.transaction { |tx| tx.query(cypher, {}) }
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(:current_driver).source_location[0])
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
- new_or_current_transaction(options[:transaction]) do |tx|
31
- query_set(tx, query_builder.queries, { commit: !options[:transaction] }.merge(options))
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(transaction, queries, options = {})
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
- queries.map do |query|
69
- result_from_data(transaction.root_tx.run(query.cypher, query.parameters))
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::Transaction.query(self, transaction: Transaction.root, wrap_level: (:core_entity if unwrapped?))
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(driver: @driver).tap do |new_query|
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)
@@ -23,9 +23,7 @@ module ActiveGraph
23
23
  end
24
24
 
25
25
  def query
26
- # `nil` drivers are just a workaround until
27
- # we phase out `Query` objects containing drivers
28
- ActiveGraph::Core::Query.new(driver: nil)
26
+ ActiveGraph::Core::Query.new
29
27
  end
30
28
  end
31
29
  end
@@ -24,11 +24,6 @@ module ActiveGraph
24
24
  end
25
25
  end
26
26
 
27
- def named_constraints
28
- result = query('CALL db.constraints()', {}, skip_instrumentation: true)
29
- result.columns.include?(:name) ? result : []
30
- end
31
-
32
27
  private
33
28
 
34
29
  def v4_filter(row)
@@ -1,7 +1,6 @@
1
1
  require 'active_graph/transaction'
2
2
  require 'active_graph/core/instrumentable'
3
3
  require 'active_graph/core/query'
4
- require 'active_graph/core/driver'
5
4
  require 'active_graph/core/responses'
6
5
 
7
6
  require 'neo4j_ruby_driver'
@@ -28,7 +28,7 @@ module ActiveGraph
28
28
  end
29
29
 
30
30
  def query(*args)
31
- ActiveGraph::Base.current_driver.query(*args)
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.current_driver.query("MATCH (n:`#{label}`) WHERE NOT EXISTS(n.#{id_property})
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.run_transaction(transactions?, &block)
66
+ transactions? ? ActiveGraph::Base.transaction(&block) : block.call
67
67
  end
68
68
 
69
69
  def log_queries
70
- subscriber = ActiveGraph::Transaction.subscribe_to_query(&method(:output))
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
- tx = ActiveGraph::Base.new_transaction
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
- count
41
- rescue ActiveGraph::Server::CypherResponse::ResponseError, Faraday::TimeoutError
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(driver)
6
- {constraints: fetch_constraint_descriptions(driver).sort,
7
- indexes: fetch_index_descriptions(driver).sort}
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(driver, schema_data, remove_missing)
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
- driver.queries do
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
- driver.query('CALL db.constraints()').map(&:description)
22
+ ActiveGraph::Base.query('CALL db.constraints()').map(&:description)
23
23
  end
24
24
 
25
25
  def fetch_index_descriptions(driver)
26
- result = driver.query('CALL db.indexes()')
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::Transaction.constraints.each_with_object({}) do |row, result|
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::Transaction.indexes.each_with_object({}) do |row, result|
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
- self.class.run_transaction { association_proxy(name).replace_with(other_nodes) }
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
- self.class.run_transaction { association_proxy(name).replace_with(other_node) }
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. If there are nodes and associations that
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
- self.class.run_transaction(pending_deferred_creations?) do
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.run_transaction do
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.run_transaction do
155
+ ActiveGraph::Base.transaction do
156
156
  node = model.create(params)
157
157
  self << node
158
- return node
158
+ node
159
159
  end
160
160
  end
161
161
 
@@ -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
@@ -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
- ActiveGraph::Base.new_driver(url || path || default_driver_path_or_url, auth_token, config)
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::Transaction.subscribe_to_query(&logger_proc)
103
- ActiveGraph::Transaction.subscribe_to_request(&logger_proc)
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
@@ -19,6 +19,7 @@ module ActiveGraph
19
19
  include ActiveGraph::Relationship::Types
20
20
  include ActiveGraph::Shared::Enum
21
21
  include ActiveGraph::Shared::PermittedAttributes
22
+ include ActiveGraph::Transactions
22
23
 
23
24
  class FrozenRelError < ActiveGraph::Error; end
24
25
 
@@ -20,16 +20,14 @@ module ActiveGraph
20
20
  end
21
21
 
22
22
  def destroy #:nodoc:
23
- tx = ActiveGraph::Base.new_transaction
24
- tx.root.after_commit { run_callbacks(:destroy_commit) {} }
25
- run_callbacks(:destroy) { super }
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
- self.class.run_transaction do |tx|
55
- tx.root.after_commit { run_callbacks(:create_commit) {} }
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
- self.class.run_transaction do |tx|
62
- tx.root.after_commit { run_callbacks(:update_commit) {} }
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
- current_transaction.mark_failed if result == false && current_transaction
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
- self.class.run_transaction do |tx|
179
+ ActiveGraph::Base.transaction do |tx|
184
180
  self.attributes = process_attributes(attributes)
185
181
  saved = save
186
- tx.mark_failed unless saved
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
- self.class.run_transaction do
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
- self.class.run_transaction do
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)
@@ -14,7 +14,7 @@ module ActiveGraph
14
14
 
15
15
  # remove?
16
16
  def neo4j_driver
17
- ActiveGraph::Base.current_driver
17
+ ActiveGraph::Base.driver
18
18
  end
19
19
 
20
20
  # remove?
@@ -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.on_establish_session do
13
- ActiveGraph::Base.new_driver(neo4j_url)
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.transaction.version > '3.0.0'
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(ActiveGraph::Base.transaction)
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::Transaction.subscribe_to_query(&method(:puts))
100
+ ActiveGraph::Base.subscribe_to_query(&method(:puts))
101
101
 
102
- ActiveGraph::Base.run_transaction do
103
- ActiveGraph::Migrations::Schema.synchronize_schema_data(ActiveGraph::Base.transaction, schema_data, args[:remove_missing])
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.run_transaction do
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
- class Transaction
8
- include ActiveGraph::Core::Querable
9
- extend ActiveGraph::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 [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
- alias failure mark_failed
71
-
72
- # If it has been marked as failed.
73
- # Aliased for legacy purposes.
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 post_close!
131
- if failed?
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 :ag_session, :tx
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.ag_session = session
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 write_transaction(config = nil, &block)
23
- send_transaction(:write_transaction, config, &block)
20
+ def transaction(**config, &block)
21
+ send_transaction(:begin_transaction, **config, &block)
24
22
  end
25
- alias transaction write_transaction
26
23
 
27
- def read_transaction(config = nil, &block)
28
- send_transaction(:read_transaction, config, &block)
24
+ def write_transaction(**config, &block)
25
+ send_transaction(:write_transaction, **config, &block)
29
26
  end
30
27
 
31
- def begin_transaction(config = nil, &block)
32
- send_transaction(:begin_transaction, config, &block)
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 = nil, &block)
38
- return yield tx if tx
39
- return reuse(ag_session, method, config, &block) if ag_session
40
- driver.session { |session| reuse(session, method, config, &block) }
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 reuse(session, method, config)
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
- yield tx
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
@@ -1,3 +1,3 @@
1
1
  module ActiveGraph
2
- VERSION = '10.0.0-beta.3'
2
+ VERSION = '10.0.0-beta.4'
3
3
  end
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.3
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-03-12 00:00:00.000000000 Z
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.0
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.0
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