active_record_compose 1.3.0 → 1.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/lib/active_record_compose/attributes.rb +5 -3
- data/lib/active_record_compose/exceptions.rb +15 -2
- data/lib/active_record_compose/model.rb +1 -1
- data/lib/active_record_compose/transaction_support/transaction_coordinator.rb +3 -3
- data/lib/active_record_compose/transaction_support.rb +21 -16
- data/lib/active_record_compose/version.rb +12 -1
- data/lib/active_record_compose.rb +4 -0
- data/sig/_internal/package_private.rbs +4 -1
- data/sig/active_record_compose.rbs +11 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 91c3305d64d7b4e8b0cf57e127b9b1e48c0a413a5749d79f1afef5d659814271
|
|
4
|
+
data.tar.gz: 321aa91ad6500b97a38f02ea70f5904c2852016eddf7fb4388186e25c83ff825
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ad550be47844182ac031aaa4c9df4c344e0b14a3173a3402c2e7d44123bd953c1b2ef4f62e0ff5ca8d49c17f688cb9a6c5385d1aeb810bb34263d7f2203cd943
|
|
7
|
+
data.tar.gz: a97affe0e201a77cb207ba0d013194c9b1a30a79611a80d4d0e133904bfd8f016e2f330a126428acdec22f248bfa2ed999df62db46a5174fe8deb3ec2ebaee84
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [1.4.0] - 2026-10-14
|
|
4
|
+
|
|
5
|
+
* Use a dedicated deprecator for deprecated APIs.
|
|
6
|
+
(https://github.com/hamajyotan/active_record_compose/pull/75)
|
|
7
|
+
* Fix `before_commit` callback timing for transactions spanning multiple database connections.
|
|
8
|
+
(https://github.com/hamajyotan/active_record_compose/pull/76)
|
|
9
|
+
- Ensure that `before_commit` callbacks are invoked at the appropriate point before the outermost transaction commits.
|
|
10
|
+
- Leave behavior unchanged when all models use a single database connection.
|
|
11
|
+
* Perform validations outside a transaction.
|
|
12
|
+
(https://github.com/hamajyotan/active_record_compose/pull/78)
|
|
13
|
+
* Execute inner models' `after_commit` callbacks before outer models' callbacks.
|
|
14
|
+
(https://github.com/hamajyotan/active_record_compose/pull/79)
|
|
15
|
+
* Add `ActiveRecordCompose::UninitializedAttribute#record`.
|
|
16
|
+
|
|
3
17
|
## [1.3.0] - 2026-08-09
|
|
4
18
|
|
|
5
19
|
* Support secondary and multiple database
|
|
@@ -167,14 +167,16 @@ module ActiveRecordCompose
|
|
|
167
167
|
|
|
168
168
|
private
|
|
169
169
|
|
|
170
|
-
|
|
170
|
+
# @private
|
|
171
|
+
def _write_attribute(...) = _require_attributes_initialized { super }
|
|
171
172
|
|
|
173
|
+
# @private
|
|
172
174
|
def attribute(...) = _require_attributes_initialized { super }
|
|
173
175
|
|
|
176
|
+
# @private
|
|
174
177
|
def _require_attributes_initialized
|
|
175
178
|
unless @attributes
|
|
176
|
-
raise ActiveRecordCompose::UninitializedAttribute
|
|
177
|
-
"No attributes have been set. Is proper initialization performed, such as calling `super` in `initialize`?"
|
|
179
|
+
raise ActiveRecordCompose::UninitializedAttribute.new(self)
|
|
178
180
|
end
|
|
179
181
|
|
|
180
182
|
yield
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActiveRecordCompose
|
|
4
|
+
# Generic Active Record Compose exception class.
|
|
5
|
+
#
|
|
6
|
+
class ActiveRecordComposeError < StandardError
|
|
7
|
+
end
|
|
8
|
+
|
|
4
9
|
# Occurs when a circular reference is detected in the containing model.
|
|
5
10
|
#
|
|
6
11
|
# @example
|
|
@@ -25,7 +30,7 @@ module ActiveRecordCompose
|
|
|
25
30
|
# inner.model = outer # There is a circular reference in the form outer > middle > inner > outer.
|
|
26
31
|
# outer.save #=> raises ActiveRecordCompose::CircularReferenceDetected
|
|
27
32
|
#
|
|
28
|
-
class CircularReferenceDetected <
|
|
33
|
+
class CircularReferenceDetected < ActiveRecordComposeError; end
|
|
29
34
|
|
|
30
35
|
# Occurs when accessing Attributes without initializing it.
|
|
31
36
|
#
|
|
@@ -40,5 +45,13 @@ module ActiveRecordCompose
|
|
|
40
45
|
# model = Model.new
|
|
41
46
|
# model.foo = 1 #=> raises ActiveRecordCompose::UninitializedAttribute
|
|
42
47
|
#
|
|
43
|
-
class UninitializedAttribute <
|
|
48
|
+
class UninitializedAttribute < ActiveRecordComposeError
|
|
49
|
+
attr_reader :record
|
|
50
|
+
|
|
51
|
+
def initialize(record = nil)
|
|
52
|
+
@record = record
|
|
53
|
+
message = "No attributes have been set. Is proper initialization performed, such as calling `super` in `initialize`?"
|
|
54
|
+
super(message)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
44
57
|
end
|
|
@@ -85,8 +85,8 @@ module ActiveRecordCompose
|
|
|
85
85
|
|
|
86
86
|
include ActiveRecordCompose::Attributes
|
|
87
87
|
include ActiveRecordCompose::Persistence
|
|
88
|
-
include ActiveRecordCompose::Validations
|
|
89
88
|
include ActiveRecordCompose::TransactionSupport
|
|
89
|
+
include ActiveRecordCompose::Validations
|
|
90
90
|
include ActiveRecordCompose::Inspectable
|
|
91
91
|
|
|
92
92
|
def initialize(attributes = {})
|
|
@@ -15,10 +15,9 @@ module ActiveRecordCompose
|
|
|
15
15
|
# but not just before any inner transactions commit.
|
|
16
16
|
#
|
|
17
17
|
def on_before_comitted
|
|
18
|
-
return
|
|
18
|
+
return unless final_transaction?
|
|
19
19
|
|
|
20
20
|
yield
|
|
21
|
-
@_before_committed_called = true
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
# It processes after_commit/after_rollback only immediately
|
|
@@ -35,10 +34,11 @@ module ActiveRecordCompose
|
|
|
35
34
|
def with_transaction_cleanup
|
|
36
35
|
yield
|
|
37
36
|
ensure
|
|
38
|
-
@_before_committed_called = false
|
|
39
37
|
transactions.reject! { _1.closed? }
|
|
40
38
|
end
|
|
41
39
|
|
|
40
|
+
def final_transaction? = transactions.one? { !_1.closed? }
|
|
41
|
+
|
|
42
42
|
def all_finished? = transactions.all? { _1.closed? }
|
|
43
43
|
|
|
44
44
|
def transactions = @transactions ||= Set.new
|
|
@@ -15,24 +15,26 @@ module ActiveRecordCompose
|
|
|
15
15
|
# steep:ignore:start
|
|
16
16
|
|
|
17
17
|
class_methods do
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
if ActiveRecord.version >= Gem::Version.new("7.2")
|
|
19
|
+
# @private
|
|
20
|
+
# @deprecated
|
|
21
|
+
def with_connection(...)
|
|
22
|
+
ActiveRecordCompose.deprecator.deprecation_warning(:with_connection, "Use `ActiveRecord::Base.with_connection` instead.")
|
|
23
|
+
ActiveRecord::Base.with_connection(...)
|
|
24
|
+
end
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
# @private
|
|
27
|
+
# @deprecated
|
|
28
|
+
def lease_connection(...)
|
|
29
|
+
ActiveRecordCompose.deprecator.deprecation_warning(:lease_connection, "Use `ActiveRecord::Base.lease_connection` instead.")
|
|
30
|
+
ActiveRecord::Base.lease_connection(...)
|
|
31
|
+
end
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
# @private
|
|
33
35
|
# @deprecated
|
|
34
36
|
def connection(...)
|
|
35
|
-
|
|
37
|
+
ActiveRecordCompose.deprecator.deprecation_warning(:connection, "Use `ActiveRecord::Base.connection` instead.")
|
|
36
38
|
ActiveRecord::Base.connection(...)
|
|
37
39
|
end
|
|
38
40
|
end
|
|
@@ -135,9 +137,12 @@ module ActiveRecordCompose
|
|
|
135
137
|
connection.transaction do |tran|
|
|
136
138
|
tran ||= ActiveTransaction.new(connection.current_transaction) # steep:ignore
|
|
137
139
|
transaction_coordinator.add_transaction(tran)
|
|
138
|
-
connection.add_transaction_record(self, ensure_finalize || has_transactional_callbacks?)
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
begin
|
|
142
|
+
inner_proc.call.tap { raise ActiveRecord::Rollback unless _1 }
|
|
143
|
+
ensure
|
|
144
|
+
connection.add_transaction_record(self, ensure_finalize || has_transactional_callbacks?)
|
|
145
|
+
end
|
|
141
146
|
end
|
|
142
147
|
end
|
|
143
148
|
end
|
|
@@ -155,7 +160,7 @@ module ActiveRecordCompose
|
|
|
155
160
|
# @private
|
|
156
161
|
def connection_pool(ar_class: default_ar_class)
|
|
157
162
|
connection_specification_name = ar_class.connection_specification_name
|
|
158
|
-
role = ar_class.current_role
|
|
163
|
+
role = ar_class.current_role # steep:ignore
|
|
159
164
|
shard = ar_class.current_shard # steep:ignore
|
|
160
165
|
connection_handler = ar_class.connection_handler # steep:ignore
|
|
161
166
|
retrieve_options = { role:, shard: }
|
|
@@ -167,7 +172,7 @@ module ActiveRecordCompose
|
|
|
167
172
|
# @private
|
|
168
173
|
def with_pool_transaction_isolation_level(connection, &block)
|
|
169
174
|
if ActiveRecord.gem_version.release >= Gem::Version.new("8.1.0")
|
|
170
|
-
isolation_level = ActiveRecord.default_transaction_isolation_level
|
|
175
|
+
isolation_level = ActiveRecord.default_transaction_isolation_level
|
|
171
176
|
connection.pool.with_pool_transaction_isolation_level(isolation_level, connection.transaction_open?, &block)
|
|
172
177
|
else
|
|
173
178
|
block.call
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module ActiveRecordCompose
|
|
4
|
-
VERSION = "1.
|
|
4
|
+
VERSION = "1.4.0"
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
def version = Gem::Version.new(VERSION)
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# @private
|
|
12
|
+
def next_major_version
|
|
13
|
+
version.segments.first + 1 # steep:ignore
|
|
14
|
+
end
|
|
15
|
+
end
|
|
5
16
|
end
|
|
@@ -11,6 +11,10 @@ require_relative "active_record_compose/model"
|
|
|
11
11
|
# Most of the functionality resides in {ActiveRecordCompose::Model}.
|
|
12
12
|
#
|
|
13
13
|
module ActiveRecordCompose
|
|
14
|
+
# @private
|
|
15
|
+
def self.deprecator
|
|
16
|
+
@deprecator ||= ActiveSupport::Deprecation.new(next_major_version, "ActiveRecordCompose") # steep:ignore
|
|
17
|
+
end
|
|
14
18
|
end
|
|
15
19
|
|
|
16
20
|
require "active_record_compose/railtie" if defined?(::Rails::Railtie)
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
module ActiveRecordCompose
|
|
2
|
+
private
|
|
3
|
+
def self.next_major_version: () -> Integer
|
|
4
|
+
|
|
2
5
|
module Attributes
|
|
3
6
|
extend ActiveSupport::Concern
|
|
4
7
|
include ActiveModel::Attributes
|
|
@@ -139,7 +142,6 @@ module ActiveRecordCompose
|
|
|
139
142
|
def transaction_coordinator: () -> ActiveRecordCompose::TransactionSupport::TransactionCoordinator
|
|
140
143
|
|
|
141
144
|
class TransactionCoordinator
|
|
142
|
-
@_before_committed_called: bool
|
|
143
145
|
@transactions: Set[ActiveRecord::ConnectionAdapters::Transaction]
|
|
144
146
|
|
|
145
147
|
def add_transaction: (ActiveRecord::ConnectionAdapters::Transaction) -> void
|
|
@@ -147,6 +149,7 @@ module ActiveRecordCompose
|
|
|
147
149
|
def on_before_comitted: () { () -> void } -> void
|
|
148
150
|
|
|
149
151
|
private
|
|
152
|
+
def final_transaction?: -> bool
|
|
150
153
|
def all_finished?: -> bool
|
|
151
154
|
def transactions: () -> Set[ActiveRecord::ConnectionAdapters::Transaction]
|
|
152
155
|
def with_transaction_cleanup: () { () -> void } -> void
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
module ActiveRecordCompose
|
|
5
5
|
VERSION: String
|
|
6
6
|
|
|
7
|
+
def self.version: () -> Gem::Version
|
|
8
|
+
def self.deprecator: () -> ActiveSupport::Deprecation
|
|
9
|
+
|
|
7
10
|
interface _ARLike
|
|
8
11
|
def save: (**untyped options) -> bool
|
|
9
12
|
def save!: (**untyped options) -> untyped
|
|
@@ -36,6 +39,9 @@ module ActiveRecordCompose
|
|
|
36
39
|
type destroy_context_type = ((^() -> boolish) | (^(ar_like) -> boolish))
|
|
37
40
|
type condition_type = ((^() -> boolish) | (^(ar_like) -> boolish))
|
|
38
41
|
|
|
42
|
+
class ActiveRecordComposeError < StandardError
|
|
43
|
+
end
|
|
44
|
+
|
|
39
45
|
class ComposedCollection
|
|
40
46
|
include ::Enumerable[ar_like]
|
|
41
47
|
|
|
@@ -47,7 +53,7 @@ module ActiveRecordCompose
|
|
|
47
53
|
def delete: (ar_like) -> ComposedCollection?
|
|
48
54
|
end
|
|
49
55
|
|
|
50
|
-
class CircularReferenceDetected <
|
|
56
|
+
class CircularReferenceDetected < ActiveRecordComposeError
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
class Model
|
|
@@ -99,6 +105,9 @@ module ActiveRecordCompose
|
|
|
99
105
|
extend Rails::Initializable::ClassMethods
|
|
100
106
|
end
|
|
101
107
|
|
|
102
|
-
class UninitializedAttribute <
|
|
108
|
+
class UninitializedAttribute < ActiveRecordComposeError
|
|
109
|
+
def initialize: (?untyped) -> void
|
|
110
|
+
|
|
111
|
+
attr_reader record: untyped
|
|
103
112
|
end
|
|
104
113
|
end
|