activerecord-wrapped_transaction 0.5.1 → 0.9.0

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.
@@ -0,0 +1,80 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ activerecord-wrapped_transaction (0.9.0)
5
+ activerecord (>= 5, < 7)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activemodel (6.0.3.1)
11
+ activesupport (= 6.0.3.1)
12
+ activerecord (6.0.3.1)
13
+ activemodel (= 6.0.3.1)
14
+ activesupport (= 6.0.3.1)
15
+ activesupport (6.0.3.1)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (>= 0.7, < 2)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ zeitwerk (~> 2.2, >= 2.2.2)
21
+ appraisal (2.3.0)
22
+ bundler
23
+ rake
24
+ thor (>= 0.14.0)
25
+ coderay (1.1.3)
26
+ concurrent-ruby (1.1.6)
27
+ database_cleaner (1.8.5)
28
+ database_cleaner-active_record (1.8.0)
29
+ activerecord
30
+ database_cleaner (~> 1.8.0)
31
+ diff-lcs (1.3)
32
+ docile (1.3.2)
33
+ i18n (1.8.3)
34
+ concurrent-ruby (~> 1.0)
35
+ method_source (1.0.0)
36
+ minitest (5.14.1)
37
+ pry (0.13.1)
38
+ coderay (~> 1.1)
39
+ method_source (~> 1.0)
40
+ rake (13.0.1)
41
+ rspec (3.9.0)
42
+ rspec-core (~> 3.9.0)
43
+ rspec-expectations (~> 3.9.0)
44
+ rspec-mocks (~> 3.9.0)
45
+ rspec-core (3.9.2)
46
+ rspec-support (~> 3.9.3)
47
+ rspec-expectations (3.9.2)
48
+ diff-lcs (>= 1.2.0, < 2.0)
49
+ rspec-support (~> 3.9.0)
50
+ rspec-mocks (3.9.1)
51
+ diff-lcs (>= 1.2.0, < 2.0)
52
+ rspec-support (~> 3.9.0)
53
+ rspec-support (3.9.3)
54
+ simplecov (0.18.5)
55
+ docile (~> 1.1)
56
+ simplecov-html (~> 0.11)
57
+ simplecov-html (0.12.2)
58
+ sqlite3 (1.4.2)
59
+ thor (1.0.1)
60
+ thread_safe (0.3.6)
61
+ tzinfo (1.2.7)
62
+ thread_safe (~> 0.1)
63
+ zeitwerk (2.3.0)
64
+
65
+ PLATFORMS
66
+ ruby
67
+
68
+ DEPENDENCIES
69
+ activerecord (~> 6, < 7)
70
+ activerecord-wrapped_transaction!
71
+ appraisal (~> 2.3.0)
72
+ database_cleaner-active_record (~> 1.8.0)
73
+ pry
74
+ rake (>= 12.3.3)
75
+ rspec (~> 3.5)
76
+ simplecov (~> 0.18.5)
77
+ sqlite3
78
+
79
+ BUNDLED WITH
80
+ 2.1.4
@@ -1,25 +1,44 @@
1
1
  require "active_record"
2
2
  require "activerecord/wrapped_transaction/version"
3
+ require "activerecord/wrapped_transaction/context"
3
4
  require "activerecord/wrapped_transaction/result"
4
5
 
5
6
  module ActiveRecord
6
7
  module WrappedTransaction
7
8
  extend ActiveSupport::Concern
8
9
 
10
+ class InvalidTransactor < ArgumentError; end
11
+
12
+ TRANSACTOR = ->(object) do
13
+ object.tap do |o|
14
+ raise InvalidTransactor, "#{object.inspect} must respond to #transaction" unless o.respond_to?(:transaction)
15
+ end
16
+ end
17
+
9
18
  included do
10
19
  delegate :wrapped_transaction, to: :class
11
20
  end
12
21
 
13
22
  class_methods do
23
+ # @param [{ Symbol => Object }] options
24
+ # @option options [Boolean] :requires_new
25
+ # @option options [String] :isolation
26
+ # @option options [Boolean] :joinable
14
27
  # @return [ActiveRecord::WrappedTransaction::Result]
15
- def wrapped_transaction(options = {}, &block)
16
- ActiveRecord::WrappedTransaction::Result.new(transactor: connection, transaction_options: options, &block)
28
+ def wrapped_transaction(**options, &block)
29
+ ActiveRecord::WrappedTransaction::Result.new(transactor: connection, **options, &block)
17
30
  end
18
31
  end
19
32
 
20
33
  class << self
34
+ # @param [#transaction] transactor
35
+ # @param [{ Symbol => Object }] options
36
+ # @option options [Boolean] :requires_new
37
+ # @option options [String] :isolation
38
+ # @option options [Boolean] :joinable
39
+ # @return [ActiveRecord::WrappedTransaction::Result]
21
40
  def call(transactor: ActiveRecord::Base, **options)
22
- ActiveRecord::WrappedTransaction::Result.new(transactor: transactor, transaction_options: options) { yield }
41
+ ActiveRecord::WrappedTransaction::Result.new(transactor: transactor, **options) { yield }
23
42
  end
24
43
  end
25
44
  end
@@ -0,0 +1,95 @@
1
+ module ActiveRecord
2
+ module WrappedTransaction
3
+ class Context
4
+ # @!attribute [r] transactor
5
+ # @return [#transaction, ActiveRecord::ConnectionAdapters::AbstractAdapter]
6
+ attr_reader :transactor
7
+
8
+ attr_reader :isolation
9
+ attr_reader :requires_new
10
+ attr_reader :joinable
11
+
12
+ # @!attribute [r] parent
13
+ # @return [ActiveRecord::WrappedTransaction::Context]
14
+ attr_reader :parent
15
+
16
+ def initialize(transactor:, requires_new: nil, isolation: nil, joinable: true, parent: nil)
17
+ @transactor = TRANSACTOR[transactor]
18
+ @requires_new = requires_new
19
+ @isolation = isolation
20
+ @joinable = joinable
21
+ @parent = parent
22
+
23
+ @transaction_options = {
24
+ requires_new: @requires_new,
25
+ isolation: @isolation,
26
+ joinable: @joinable
27
+ }.freeze
28
+ end
29
+
30
+ # @!attribute [r] depth
31
+ # The depth of the wrapped transaction
32
+ # @return [Integer]
33
+ def depth
34
+ @depth ||= calculate_depth
35
+ end
36
+
37
+ # @return [ActiveRecord::WrappedContext::Result]
38
+ def maybe(**new_options, &block)
39
+ new_options[:joinable] = false
40
+ new_options[:requires_new] = true
41
+
42
+ build_result(**new_options, &block)
43
+ end
44
+
45
+ # @return [ActiveRecord::WrappedContext::Result]
46
+ def wrap(**new_options, &block)
47
+ build_result(**new_options, &block)
48
+ end
49
+
50
+ # Cancel the current transaction with an arbitrary `reason`.
51
+ #
52
+ # @param [String] reason
53
+ # @return [void]
54
+ def cancel!(reason = nil)
55
+ throw :cancel_transaction, reason
56
+ end
57
+
58
+ # @api private
59
+ def wrap_transaction
60
+ transactor.transaction **@transaction_options do
61
+ yield
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def build_result(**new_options, &block)
68
+ options = build_result_options(**new_options)
69
+
70
+ Result.new(**options, &block)
71
+ end
72
+
73
+ def build_result_options(requires_new: @requires_new, isolation: @isolation, joinable: @joinable, **unused_options)
74
+ # :nocov:
75
+ unused_options.each do |key, value|
76
+ warn "received unused option: #{key.inspect} => #{value.inspect}"
77
+ end
78
+ # :nocov:
79
+
80
+ {
81
+ transactor: @transactor,
82
+ requires_new: requires_new,
83
+ isolation: isolation,
84
+ joinable: joinable,
85
+ parent_context: self
86
+ }
87
+ end
88
+
89
+ # @return [Integer]
90
+ def calculate_depth
91
+ parent.nil? ? 0 : parent.depth + 1
92
+ end
93
+ end
94
+ end
95
+ end
@@ -15,32 +15,23 @@ module ActiveRecord
15
15
  # @return [Exception, nil]
16
16
  attr_reader :error
17
17
 
18
- # @!attribute [r] result
19
- # @return [Object, nil]
20
- attr_reader :result
21
-
22
- # @!attribute [r] transactor
23
- # @return [#transaction, ActiveRecord::ConnectionAdapters::AbstractAdapter]
24
- attr_reader :transactor
25
-
26
18
  # @param [#transaction, ActiveRecord::ConnectionAdapters::AbstractAdapter] transactor
19
+ # @param [ActiveRecord::WrappedTransaction::Context] parent_context
20
+ # @param [{ Symbol => Object }] options
21
+ # @option options [Boolean] :requires_new
22
+ # @option options [String] :isolation
23
+ # @option options [Boolean] :joinable
27
24
  # @yield A block that goes in the transaction.
28
25
  # @yieldreturn [Object]
29
- def initialize(transactor: ActiveRecord::Base, transaction_options: {})
30
- unless block_given?
31
- raise ArgumentError, "Must call with a block to run in the transaction"
32
- end
26
+ def initialize(transactor: ActiveRecord::Base, parent_context: nil, **options)
27
+ raise ArgumentError, "Must call with a block to run in the transaction" unless block_given?
33
28
 
34
- unless transactor.respond_to?(:transaction)
35
- raise ArgumentError, "transactor `#{transactor.inspect} must respond to :transaction"
36
- else
37
- @transactor = transactor
38
- end
29
+ @context = Context.new transactor: transactor, parent: parent_context, **options
39
30
 
40
- wrap_transaction transaction_options do
31
+ wrap_transaction do
41
32
  execute_transaction do
42
33
  watch_for_cancellation do
43
- @result = yield
34
+ @result = unwrap yield @context
44
35
  end
45
36
  end
46
37
  end
@@ -52,21 +43,28 @@ module ActiveRecord
52
43
  @cancelled
53
44
  end
54
45
 
55
- def success?
56
- @success
46
+ # @!attribute [r] result
47
+ # @return [Object, nil]
48
+ def result
49
+ @result if success?
57
50
  end
58
51
 
59
52
  def rolled_back?
60
53
  !success?
61
54
  end
62
55
 
56
+ def success?
57
+ @success
58
+ end
59
+
63
60
  private
64
- def wrap_transaction(transaction_options = {})
65
- caught = transactor.transaction(transaction_options) do
61
+
62
+ def wrap_transaction
63
+ caught = @context.wrap_transaction do
66
64
  yield
67
65
  end
68
66
  ensure
69
- @success = caught.eql?(TXN_COMPLETE)
67
+ @success = caught.eql? TXN_COMPLETE
70
68
  end
71
69
 
72
70
  def execute_transaction
@@ -82,11 +80,18 @@ module ActiveRecord
82
80
  def watch_for_cancellation
83
81
  cancellation_reason = catch(:cancel_transaction) { yield; NOT_CANCELLED }
84
82
 
85
- unless cancellation_reason.eql?(NOT_CANCELLED)
86
- @cancelled = true
87
- @cancellation_reason = cancellation_reason
88
- raise ActiveRecord::Rollback, "Cancelled transaction"
89
- end
83
+ return if cancellation_reason.eql? NOT_CANCELLED
84
+
85
+ @cancelled = true
86
+ @cancellation_reason = cancellation_reason
87
+
88
+ raise ActiveRecord::Rollback, "Cancelled transaction"
89
+ end
90
+
91
+ def unwrap(value)
92
+ return value unless value.kind_of?(self.class) && value.success?
93
+
94
+ value.result
90
95
  end
91
96
  end
92
97
  end
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module WrappedTransaction
3
- VERSION = "0.5.1"
3
+ VERSION = "0.9.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord-wrapped_transaction
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexa Grey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-26 00:00:00.000000000 Z
11
+ date: 2020-06-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,120 +16,92 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '5'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '6'
22
+ version: '7'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '3.2'
29
+ version: '5'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '6'
32
+ version: '7'
33
33
  - !ruby/object:Gem::Dependency
34
- name: simplecov
35
- requirement: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - "~>"
38
- - !ruby/object:Gem::Version
39
- version: 0.12.0
40
- type: :development
41
- prerelease: false
42
- version_requirements: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - "~>"
45
- - !ruby/object:Gem::Version
46
- version: 0.12.0
47
- - !ruby/object:Gem::Dependency
48
- name: bundler
34
+ name: appraisal
49
35
  requirement: !ruby/object:Gem::Requirement
50
36
  requirements:
51
37
  - - "~>"
52
38
  - !ruby/object:Gem::Version
53
- version: '1.11'
39
+ version: 2.3.0
54
40
  type: :development
55
41
  prerelease: false
56
42
  version_requirements: !ruby/object:Gem::Requirement
57
43
  requirements:
58
44
  - - "~>"
59
45
  - !ruby/object:Gem::Version
60
- version: '1.11'
46
+ version: 2.3.0
61
47
  - !ruby/object:Gem::Dependency
62
- name: rake
48
+ name: simplecov
63
49
  requirement: !ruby/object:Gem::Requirement
64
50
  requirements:
65
51
  - - "~>"
66
52
  - !ruby/object:Gem::Version
67
- version: '10.0'
53
+ version: 0.18.5
68
54
  type: :development
69
55
  prerelease: false
70
56
  version_requirements: !ruby/object:Gem::Requirement
71
57
  requirements:
72
58
  - - "~>"
73
59
  - !ruby/object:Gem::Version
74
- version: '10.0'
60
+ version: 0.18.5
75
61
  - !ruby/object:Gem::Dependency
76
- name: rspec
62
+ name: database_cleaner-active_record
77
63
  requirement: !ruby/object:Gem::Requirement
78
64
  requirements:
79
65
  - - "~>"
80
66
  - !ruby/object:Gem::Version
81
- version: '3.5'
67
+ version: 1.8.0
82
68
  type: :development
83
69
  prerelease: false
84
70
  version_requirements: !ruby/object:Gem::Requirement
85
71
  requirements:
86
72
  - - "~>"
87
73
  - !ruby/object:Gem::Version
88
- version: '3.5'
74
+ version: 1.8.0
89
75
  - !ruby/object:Gem::Dependency
90
- name: pry
76
+ name: rake
91
77
  requirement: !ruby/object:Gem::Requirement
92
78
  requirements:
93
79
  - - ">="
94
80
  - !ruby/object:Gem::Version
95
- version: '0'
81
+ version: 12.3.3
96
82
  type: :development
97
83
  prerelease: false
98
84
  version_requirements: !ruby/object:Gem::Requirement
99
85
  requirements:
100
86
  - - ">="
101
87
  - !ruby/object:Gem::Version
102
- version: '0'
103
- - !ruby/object:Gem::Dependency
104
- name: pg
105
- requirement: !ruby/object:Gem::Requirement
106
- requirements:
107
- - - "~>"
108
- - !ruby/object:Gem::Version
109
- version: 0.18.0
110
- type: :development
111
- prerelease: false
112
- version_requirements: !ruby/object:Gem::Requirement
113
- requirements:
114
- - - "~>"
115
- - !ruby/object:Gem::Version
116
- version: 0.18.0
88
+ version: 12.3.3
117
89
  - !ruby/object:Gem::Dependency
118
- name: mysql2
90
+ name: rspec
119
91
  requirement: !ruby/object:Gem::Requirement
120
92
  requirements:
121
93
  - - "~>"
122
94
  - !ruby/object:Gem::Version
123
- version: 0.4.4
95
+ version: '3.5'
124
96
  type: :development
125
97
  prerelease: false
126
98
  version_requirements: !ruby/object:Gem::Requirement
127
99
  requirements:
128
100
  - - "~>"
129
101
  - !ruby/object:Gem::Version
130
- version: 0.4.4
102
+ version: '3.5'
131
103
  - !ruby/object:Gem::Dependency
132
- name: sqlite3
104
+ name: pry
133
105
  requirement: !ruby/object:Gem::Requirement
134
106
  requirements:
135
107
  - - ">="
@@ -149,22 +121,39 @@ executables: []
149
121
  extensions: []
150
122
  extra_rdoc_files: []
151
123
  files:
124
+ - ".github/workflows/main.yml"
152
125
  - ".gitignore"
153
126
  - ".rspec"
154
- - ".travis.yml"
127
+ - Appraisals
155
128
  - CODE_OF_CONDUCT.md
156
129
  - Gemfile
157
130
  - LICENSE.txt
158
131
  - README.md
159
132
  - Rakefile
160
133
  - activerecord-wrapped_transaction.gemspec
134
+ - bin/appraisal
161
135
  - bin/console
136
+ - bin/rake
137
+ - bin/rspec
162
138
  - bin/setup
163
139
  - db/connection.rb
164
140
  - db/models.rb
165
141
  - db/schema.rb
142
+ - gemfiles/rails_5_mysql2.gemfile
143
+ - gemfiles/rails_5_mysql2.gemfile.lock
144
+ - gemfiles/rails_5_pg.gemfile
145
+ - gemfiles/rails_5_pg.gemfile.lock
146
+ - gemfiles/rails_5_sqlite3.gemfile
147
+ - gemfiles/rails_5_sqlite3.gemfile.lock
148
+ - gemfiles/rails_6_mysql2.gemfile
149
+ - gemfiles/rails_6_mysql2.gemfile.lock
150
+ - gemfiles/rails_6_pg.gemfile
151
+ - gemfiles/rails_6_pg.gemfile.lock
152
+ - gemfiles/rails_6_sqlite3.gemfile
153
+ - gemfiles/rails_6_sqlite3.gemfile.lock
166
154
  - lib/activerecord-wrapped_transaction.rb
167
155
  - lib/activerecord/wrapped_transaction.rb
156
+ - lib/activerecord/wrapped_transaction/context.rb
168
157
  - lib/activerecord/wrapped_transaction/result.rb
169
158
  - lib/activerecord/wrapped_transaction/version.rb
170
159
  homepage: https://github.com/scryptmouse/activerecord-wrapped_transaction
@@ -186,8 +175,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
175
  - !ruby/object:Gem::Version
187
176
  version: '0'
188
177
  requirements: []
189
- rubyforge_project:
190
- rubygems_version: 2.4.5
178
+ rubygems_version: 3.1.4
191
179
  signing_key:
192
180
  specification_version: 4
193
181
  summary: Wrap transactions in a manner that detects if the transaction completed