granite 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eee58f357db73ca54fa35ec5a68a13081bd450a8
4
- data.tar.gz: 1042435a47b006d54caafc174552863a2024a52d
3
+ metadata.gz: f9bc00868502247ad725644cccc110d93845426e
4
+ data.tar.gz: '09710e9fbf2c004ef8d369869e3479f92377b51f'
5
5
  SHA512:
6
- metadata.gz: 59143c029f08dae76509be73e06b653eedbfb29b98cf8b79ffebcd0eb0183fd63fe9312a0fa51c8d7806097e5a70d7168e87e116c45ce7e16af3211886b03ed4
7
- data.tar.gz: f3d6579fbd80170a55a3fef47e90db59236087a0ecd4b14c1f54f145553b38bc118efd7f24a535b5d6225143511db18b26f82187bcebb3f384063c03bdc997f2
6
+ metadata.gz: 29d0c0a27c84fb772a96af9b1fd110d0ea1453b0d47252c803ba29f32201c6cd50a9665da4137ba8349ec7c0cd01c9dddca7e408d8054daec694adfe8442d931
7
+ data.tar.gz: 6c7d51a1f438c7d1958d261f5f7e51be1aa38adf161877ef96500b3a5d19069907f7d615f0335ca63f898a5b06268afeb40f72f3bf040b610e41abebb683f6ef
@@ -0,0 +1,39 @@
1
+ module Granite
2
+ class Action
3
+ module ExceptionsHandling
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :_exception_handlers, instance_writer: false
8
+ self._exception_handlers = {}
9
+
10
+ protected :_exception_handlers
11
+ end
12
+
13
+ module ClassMethods
14
+ # Register default handler for exceptions thrown inside execute_perform! and after_commit methods.
15
+ # @param klass Exception class, could be parent class too [Class]
16
+ # @param block [Block<Exception>] with default behavior for handling specified
17
+ # type exceptions. First block argument is raised exception instance.
18
+ #
19
+ # @return [Hash<Class, Proc>] Registered handlers
20
+ def handle_exception(klass, &block)
21
+ self._exception_handlers = _exception_handlers.merge(klass => block)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def handled_exceptions
28
+ _exception_handlers.keys
29
+ end
30
+
31
+ def handle_exception(e)
32
+ klass = e.class.ancestors.detect do |ancestor|
33
+ ancestor <= Exception && _exception_handlers[ancestor]
34
+ end
35
+ instance_exec(e, &_exception_handlers[klass]) if klass
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,3 +1,4 @@
1
+ require 'granite/action/exceptions_handling'
1
2
  require 'granite/action/transaction'
2
3
  require 'granite/action/error'
3
4
 
@@ -17,28 +18,14 @@ module Granite
17
18
  module Performing
18
19
  extend ActiveSupport::Concern
19
20
 
21
+ include ExceptionsHandling
20
22
  include Transaction
21
23
 
22
24
  included do
23
- class_attribute :_exception_handlers, instance_writer: false
24
- self._exception_handlers = {}
25
-
26
- protected :_exception_handlers
27
-
28
25
  define_callbacks :execute_perform
29
26
  end
30
27
 
31
28
  module ClassMethods
32
- # Register default handler for exceptions thrown inside execute_perform! method.
33
- # @param klass Exception class, could be parent class too [Class]
34
- # @param block [Block<Exception>] with default behavior for handling specified
35
- # type exceptions. First block argument is raised exception instance.
36
- #
37
- # @return [Hash<Class, Proc>] Registered handlers
38
- def handle_exception(klass, &block)
39
- self._exception_handlers = _exception_handlers.merge(klass => block)
40
- end
41
-
42
29
  def perform(*)
43
30
  fail 'Perform block declaration was removed! Please declare `private def execute_perform!(*)` method'
44
31
  end
@@ -54,7 +41,7 @@ module Granite
54
41
  # using `:on`)
55
42
  # @return [Object] result of execute_perform! method execution or false in case of errors
56
43
  def perform(context: nil, **options)
57
- transactional do
44
+ transaction do
58
45
  valid?(context) && perform_action(options)
59
46
  end
60
47
  end
@@ -72,7 +59,7 @@ module Granite
72
59
  # @raise [Granite::Action::ValidationError] Action or associated objects are invalid
73
60
  # @raise [NotImplementedError] execute_perform! method was not defined yet
74
61
  def perform!(context: nil, **options)
75
- transactional do
62
+ transaction do
76
63
  validate!(context)
77
64
  perform_action!(**options)
78
65
  end
@@ -88,7 +75,7 @@ module Granite
88
75
  # @raise [NotImplementedError] execute_perform! method was not defined yet
89
76
  def try_perform!(context: nil, **options)
90
77
  return unless satisfy_preconditions?
91
- transactional do
78
+ transaction do
92
79
  validate!(context)
93
80
  perform_action!(**options)
94
81
  end
@@ -108,7 +95,7 @@ module Granite
108
95
  result = run_callbacks(:execute_perform) { execute_perform!(options) }
109
96
  @_action_performed = true
110
97
  result || true
111
- rescue *_exception_handlers.keys => e
98
+ rescue *handled_exceptions => e
112
99
  handle_exception(e)
113
100
  raise_validation_error(e) if raise_errors
114
101
  raise Rollback
@@ -121,13 +108,6 @@ module Granite
121
108
  def execute_perform!(**_options)
122
109
  fail NotImplementedError, "BA perform body MUST be defined for #{self}"
123
110
  end
124
-
125
- def handle_exception(e)
126
- klass = e.class.ancestors.detect do |ancestor|
127
- ancestor <= Exception && _exception_handlers[ancestor]
128
- end
129
- instance_exec(e, &_exception_handlers[klass]) if klass
130
- end
131
111
  end
132
112
  end
133
113
  end
@@ -1,40 +1,44 @@
1
+ require 'granite/action/transaction_manager'
2
+
1
3
  module Granite
2
4
  class Action
3
- class Rollback < defined?(ActiveRecord) ? ActiveRecord::Rollback : StandardError
4
- end
5
-
6
5
  module Transaction
7
6
  extend ActiveSupport::Concern
8
7
 
9
- private
10
-
11
- def transactional(&block)
12
- if transactional?
13
- yield
14
- else
15
- @_transactional = true
16
- result = transaction(&block) || false
17
- @_transactional = nil
18
- result
19
- end
8
+ included do
9
+ define_callbacks :commit
20
10
  end
21
11
 
22
- def transactional?
23
- # Fuck the police!
24
- !(!@_transactional)
12
+ module ClassMethods
13
+ delegate :transaction, to: :'Granite::Action::TransactionManager'
14
+
15
+ private
16
+
17
+ # Defines a callback which will be triggered right after transaction committed
18
+ # Uses the same arguments as `ActiveSupport::Callbacks.set_callback` except for the first two
19
+ #
20
+ def after_commit(*args, &block)
21
+ set_callback :commit, :after, *args, &block
22
+ end
25
23
  end
26
24
 
27
- def transaction(&block)
28
- if defined?(ActiveRecord::Base)
29
- ActiveRecord::Base.transaction(&block)
30
- else
25
+ def run_callbacks(event)
26
+ if event.to_s == 'commit'
31
27
  begin
32
- yield
33
- rescue Granite::Action::Rollback
34
- false
28
+ super event
29
+ rescue *handled_exceptions => e
30
+ handle_exception(e)
35
31
  end
32
+ else
33
+ super event
36
34
  end
37
35
  end
36
+
37
+ private
38
+
39
+ def transaction(&block)
40
+ self.class.transaction(trigger_callbacks_for: self, &block)
41
+ end
38
42
  end
39
43
  end
40
44
  end
@@ -0,0 +1,86 @@
1
+ module Granite
2
+ class Action
3
+ class Rollback < defined?(ActiveRecord) ? ActiveRecord::Rollback : StandardError
4
+ end
5
+
6
+ module TransactionManager
7
+ class << self
8
+ # Runs a block in a transaction
9
+ # It will open a new transaction or append a block to the current one if it exists
10
+ #
11
+ # @param [Object] trigger_callbacks_for - object which will receive `run_callbacks(:commit)` after transaction commited
12
+ # @return [Object] result of a block
13
+ def transaction(trigger_callbacks_for: nil, &block)
14
+ (callback_listeners << trigger_callbacks_for) if trigger_callbacks_for
15
+
16
+ if in_a_transaction?
17
+ yield
18
+ else
19
+ wrap_in_transaction_with_callbacks(&block)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ IN_A_TRANSACTION_KEY = :granite_transaction_manager_in_a_transaction
26
+ CALLBACK_LISTENERS_KEY = :granite_transaction_manager_callback_listeners
27
+
28
+ def callback_listeners
29
+ Thread.current[CALLBACK_LISTENERS_KEY] ||= []
30
+ end
31
+
32
+ def in_a_transaction?
33
+ !!(Thread.current[IN_A_TRANSACTION_KEY])
34
+ end
35
+
36
+ def in_a_transaction=(value)
37
+ Thread.current[IN_A_TRANSACTION_KEY] = value
38
+ end
39
+
40
+ def wrap_in_transaction_with_callbacks(&block)
41
+ self.in_a_transaction = true
42
+
43
+ result = wrap_in_transaction(&block) || false
44
+
45
+ trigger_callbacks if result
46
+
47
+ result
48
+ ensure
49
+ callback_listeners.clear
50
+ self.in_a_transaction = nil
51
+ end
52
+
53
+ def wrap_in_transaction(&block)
54
+ if defined?(ActiveRecord::Base)
55
+ ActiveRecord::Base.transaction(&block)
56
+ else
57
+ begin
58
+ yield
59
+ rescue Granite::Action::Rollback
60
+ false
61
+ end
62
+ end
63
+ end
64
+
65
+ def trigger_callbacks
66
+ collected_errors = []
67
+
68
+ callback_listeners.reverse.each do |listener|
69
+ begin
70
+ listener.run_callbacks :commit
71
+ rescue StandardError => e
72
+ collected_errors << e
73
+ end
74
+ end
75
+
76
+ if collected_errors.any?
77
+ collected_errors[1..-1].each do |error|
78
+ ActiveData.config.logger.error "Unhandled error in callback: #{error.inspect}\n#{error.backtrace.join("\n")}"
79
+ end
80
+ fail collected_errors.first
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,3 +1,3 @@
1
1
  module Granite
2
- VERSION = '0.8.0'.freeze
2
+ VERSION = '0.8.1'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: granite
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Arkadiy Zabazhanov & friends
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-15 00:00:00.000000000 Z
11
+ date: 2018-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -280,6 +280,7 @@ files:
280
280
  - lib/granite.rb
281
281
  - lib/granite/action.rb
282
282
  - lib/granite/action/error.rb
283
+ - lib/granite/action/exceptions_handling.rb
283
284
  - lib/granite/action/performer.rb
284
285
  - lib/granite/action/performing.rb
285
286
  - lib/granite/action/policies.rb
@@ -292,6 +293,7 @@ files:
292
293
  - lib/granite/action/projectors.rb
293
294
  - lib/granite/action/subject.rb
294
295
  - lib/granite/action/transaction.rb
296
+ - lib/granite/action/transaction_manager.rb
295
297
  - lib/granite/action/types.rb
296
298
  - lib/granite/action/types/collection.rb
297
299
  - lib/granite/base.rb