active_record_compose 0.11.2 → 0.12.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/.yardopts +4 -0
- data/CHANGELOG.md +29 -0
- data/README.md +6 -5
- data/lib/active_record_compose/attributes/attribute_predicate.rb +29 -0
- data/lib/active_record_compose/attributes/delegation.rb +46 -0
- data/lib/active_record_compose/attributes/querying.rb +62 -0
- data/lib/active_record_compose/attributes.rb +153 -0
- data/lib/active_record_compose/callbacks.rb +22 -0
- data/lib/active_record_compose/composed_collection.rb +16 -9
- data/lib/active_record_compose/model.rb +355 -17
- data/lib/active_record_compose/persistence.rb +13 -19
- data/lib/active_record_compose/transaction_support.rb +12 -10
- data/lib/active_record_compose/validations.rb +4 -0
- data/lib/active_record_compose/version.rb +1 -1
- data/lib/active_record_compose/wrapped_model.rb +4 -2
- data/lib/active_record_compose.rb +4 -0
- data/sig/_internal/package_private.rbs +56 -34
- data/sig/active_record_compose.rbs +3 -7
- metadata +9 -6
- data/lib/active_record_compose/attribute_querying.rb +0 -67
- data/lib/active_record_compose/delegate_attribute.rb +0 -95
@@ -1,39 +1,377 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "
|
4
|
-
require_relative "attribute_querying"
|
3
|
+
require_relative "attributes"
|
5
4
|
require_relative "composed_collection"
|
6
|
-
require_relative "delegate_attribute"
|
7
|
-
require_relative "transaction_support"
|
8
5
|
require_relative "persistence"
|
6
|
+
require_relative "transaction_support"
|
9
7
|
require_relative "validations"
|
10
8
|
|
11
9
|
module ActiveRecordCompose
|
10
|
+
# This is the core class of {ActiveRecordCompose}.
|
11
|
+
#
|
12
|
+
# By defining subclasses of this model, you can use ActiveRecordCompose functionality in your application.
|
13
|
+
# It has the basic functionality of `ActiveModel::Model` and `ActiveModel::Attributes`,
|
14
|
+
# and also provides aggregation of multiple models and atomic updates through transaction control.
|
15
|
+
# @example Example of model registration.
|
16
|
+
# class AccountRegistration < ActiveRecordCompose::Model
|
17
|
+
# def initialize(account = Account.new, attributes = {})
|
18
|
+
# @account = account
|
19
|
+
# @profile = @account.build_profile
|
20
|
+
# models << account << profile
|
21
|
+
# super(attributes)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# attribute :register_confirmation, :boolean, default: false
|
25
|
+
# delegate_attribute :name, :email, to: :account
|
26
|
+
# delegate_attribute :firstname, :lastname, :age, to: :profile
|
27
|
+
#
|
28
|
+
# validates :register_confirmation, presence: true
|
29
|
+
#
|
30
|
+
# private
|
31
|
+
#
|
32
|
+
# attr_reader :account, :profile
|
33
|
+
# end
|
34
|
+
# @example Multiple model update once.
|
35
|
+
# registration = AccountRegistration.new
|
36
|
+
# registration.assign_attributes(
|
37
|
+
# name: "alice-in-wonderland",
|
38
|
+
# email: "alice@example.com",
|
39
|
+
# firstname: "Alice",
|
40
|
+
# lastname: "Smith",
|
41
|
+
# age: 24,
|
42
|
+
# register_confirmation: true
|
43
|
+
# )
|
44
|
+
#
|
45
|
+
# registration.save! # Register Account and Profile models at the same time.
|
46
|
+
# Account.count # => (0 ->) 1
|
47
|
+
# Profile.count # => (0 ->) 1
|
48
|
+
# @example Attribute delegation.
|
49
|
+
# account = Account.new
|
50
|
+
# account.name = "foo"
|
51
|
+
#
|
52
|
+
# registration = AccountRegistration.new(account)
|
53
|
+
# registration.name # => "foo" (delegated)
|
54
|
+
# registration.name? # => true (delegated attribute method + `?`)
|
55
|
+
#
|
56
|
+
# registration.name = "bar" # => updates account.name
|
57
|
+
# account.name # => "bar"
|
58
|
+
# account.name? # => true
|
59
|
+
#
|
60
|
+
# registration.attributes # => { "original_attribute" => "qux", "name" => "bar" }
|
61
|
+
# @example Aggregate errors on invalid.
|
62
|
+
# registration = AccountRegistration.new
|
63
|
+
#
|
64
|
+
# registration.name = "alice-in-wonderland"
|
65
|
+
# registration.firstname = "Alice"
|
66
|
+
# registration.age = 18
|
67
|
+
#
|
68
|
+
# registration.valid?
|
69
|
+
# #=> false
|
70
|
+
#
|
71
|
+
# # The error contents of the objects stored in models are aggregated.
|
72
|
+
# # For example, direct access to errors in Account#email.
|
73
|
+
# registration.errors[:email].to_a # Account#email
|
74
|
+
# #=> ["can't be blank"]
|
75
|
+
#
|
76
|
+
# # Of course, the validation defined for itself is also working.
|
77
|
+
# registration.errors[:register_confirmation].to_a
|
78
|
+
# #=> ["can't be blank"]
|
79
|
+
#
|
80
|
+
# registration.errors.to_a
|
81
|
+
# #=> ["Email can't be blank", "Lastname can't be blank", "Register confirmation can't be blank"]
|
12
82
|
class Model
|
13
83
|
include ActiveModel::Model
|
14
|
-
include ActiveModel::Attributes
|
15
84
|
|
16
|
-
include ActiveRecordCompose::
|
17
|
-
include ActiveRecordCompose::Callbacks
|
18
|
-
include ActiveRecordCompose::DelegateAttribute
|
85
|
+
include ActiveRecordCompose::Attributes
|
19
86
|
include ActiveRecordCompose::Persistence
|
20
87
|
include ActiveRecordCompose::Validations
|
88
|
+
include ActiveRecordCompose::TransactionSupport
|
89
|
+
|
90
|
+
begin
|
91
|
+
# @group Model Core
|
92
|
+
|
93
|
+
# @!method self.delegate_attribute(*attributes, to:, allow_nil: false)
|
94
|
+
# Provides a method of attribute access to the encapsulated model.
|
95
|
+
#
|
96
|
+
# It provides a way to access the attributes of the model it encompasses,
|
97
|
+
# allowing transparent access as if it had those attributes itself.
|
98
|
+
#
|
99
|
+
# @param [Array<Symbol, String>] attributes
|
100
|
+
# attributes A variable-length list of attribute names to delegate.
|
101
|
+
# @param [Symbol, String] to
|
102
|
+
# The target object to which attributes are delegated (keyword argument).
|
103
|
+
# @param [Boolean] allow_nil
|
104
|
+
# allow_nil Whether to allow nil values. Defaults to false.
|
105
|
+
# @example Basic usage
|
106
|
+
# delegate_attribute :name, :email, to: :profile
|
107
|
+
# @example Allowing nil
|
108
|
+
# delegate_attribute :bio, to: :profile, allow_nil: true
|
109
|
+
# @see Module#delegate for similar behavior in ActiveSupport
|
110
|
+
|
111
|
+
# @!method self.attribute_names
|
112
|
+
# Returns a array of attribute name.
|
113
|
+
# Attributes declared with {.delegate_attribute} are also merged.
|
114
|
+
#
|
115
|
+
# @see #attribute_names
|
116
|
+
# @return [Array<String>] array of attribute name.
|
117
|
+
|
118
|
+
# @!method attribute_names
|
119
|
+
# Returns a array of attribute name.
|
120
|
+
# Attributes declared with {.delegate_attribute} are also merged.
|
121
|
+
#
|
122
|
+
# class Foo < ActiveRecordCompose::Base
|
123
|
+
# def initialize(attributes = {})
|
124
|
+
# @account = Account.new
|
125
|
+
# super
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
# attribute :confirmation, :boolean, default: false # plain attribute
|
129
|
+
# delegate_attribute :name, to: :account # delegated attribute
|
130
|
+
#
|
131
|
+
# private
|
132
|
+
#
|
133
|
+
# attr_reader :account
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# Foo.attribute_names # Returns the merged state of plain and delegated attributes
|
137
|
+
# # => ["confirmation" ,"name"]
|
138
|
+
#
|
139
|
+
# foo = Foo.new
|
140
|
+
# foo.attribute_names # Similar behavior for instance method version
|
141
|
+
# # => ["confirmation", "name"]
|
142
|
+
#
|
143
|
+
# @see #attributes
|
144
|
+
# @return [Array<String>] array of attribute name.
|
145
|
+
|
146
|
+
# @!method attributes
|
147
|
+
# Returns a hash with the attribute name as key and the attribute value as value.
|
148
|
+
# Attributes declared with {.delegate_attribute} are also merged.
|
149
|
+
#
|
150
|
+
# class Foo < ActiveRecordCompose::Base
|
151
|
+
# def initialize(attributes = {})
|
152
|
+
# @account = Account.new
|
153
|
+
# super
|
154
|
+
# end
|
155
|
+
#
|
156
|
+
# attribute :confirmation, :boolean, default: false # plain attribute
|
157
|
+
# delegate_attribute :name, to: :account # delegated attribute
|
158
|
+
#
|
159
|
+
# private
|
160
|
+
#
|
161
|
+
# attr_reader :account
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# foo = Foo.new
|
165
|
+
# foo.name = "Alice"
|
166
|
+
# foo.confirmation = true
|
167
|
+
#
|
168
|
+
# foo.attributes # Returns the merged state of plain and delegated attributes
|
169
|
+
# # => { "confirmation" => true, "name" => "Alice" }
|
170
|
+
#
|
171
|
+
# @return [Hash<String, Object>] hash with the attribute name as key and the attribute value as value.
|
172
|
+
|
173
|
+
# @!method persisted?
|
174
|
+
# Returns true if model is persisted.
|
175
|
+
#
|
176
|
+
# By overriding this definition, you can control the callbacks that are triggered when a save is made.
|
177
|
+
# For example, returning false will trigger before_create, around_create and after_create,
|
178
|
+
# and returning true will trigger {.before_update}, {.around_update} and {.after_update}.
|
179
|
+
#
|
180
|
+
# @return [Boolean] returns true if model is persisted.
|
181
|
+
# @example
|
182
|
+
# # A model where persistence is always false
|
183
|
+
# class Foo < ActiveRecordCompose::Model
|
184
|
+
# before_save { puts "before_save called" }
|
185
|
+
# before_create { puts "before_create called" }
|
186
|
+
# before_update { puts "before_update called" }
|
187
|
+
# after_update { puts "after_update called" }
|
188
|
+
# after_create { puts "after_create called" }
|
189
|
+
# after_save { puts "after_save called" }
|
190
|
+
#
|
191
|
+
# def persisted? = false
|
192
|
+
# end
|
193
|
+
#
|
194
|
+
# # A model where persistence is always true
|
195
|
+
# class Bar < Foo
|
196
|
+
# def persisted? = true
|
197
|
+
# end
|
198
|
+
#
|
199
|
+
# Foo.new.save!
|
200
|
+
# # before_save called
|
201
|
+
# # before_create called
|
202
|
+
# # after_create called
|
203
|
+
# # after_save called
|
204
|
+
#
|
205
|
+
# Bar.new.save!
|
206
|
+
# # before_save called
|
207
|
+
# # before_update called
|
208
|
+
# # after_update called
|
209
|
+
# # after_save called
|
210
|
+
|
211
|
+
# @endgroup
|
212
|
+
|
213
|
+
# @group Validations
|
214
|
+
|
215
|
+
# @!method valid?(context = nil)
|
216
|
+
# Runs all the validations and returns the result as true or false.
|
217
|
+
# @param context Validation context.
|
218
|
+
# @return [Boolean] true on success, false on failure.
|
219
|
+
|
220
|
+
# @!method validate(context = nil)
|
221
|
+
# Alias for {#valid?}
|
222
|
+
# @see #valid? Validation context.
|
223
|
+
# @param context
|
224
|
+
# @return [Boolean] true on success, false on failure.
|
225
|
+
|
226
|
+
# @!method validate!(context = nil)
|
227
|
+
# @see #valid?
|
228
|
+
# Runs all the validations within the specified context.
|
229
|
+
# no errors are found, raises `ActiveRecord::RecordInvalid` otherwise.
|
230
|
+
# @param context Validation context.
|
231
|
+
# @raise ActiveRecord::RecordInvalid
|
232
|
+
|
233
|
+
# @!method errors
|
234
|
+
# Returns the `ActiveModel::Errors` object that holds all information about attribute error messages.
|
235
|
+
#
|
236
|
+
# The `ActiveModel::Base` implementation itself,
|
237
|
+
# but also aggregates error information for objects stored in {#models} when validation is performed.
|
238
|
+
#
|
239
|
+
# class Account < ActiveRecord::Base
|
240
|
+
# validates :name, :email, presence: true
|
241
|
+
# end
|
242
|
+
#
|
243
|
+
# class AccountRegistration < ActiveRecordCompose::Model
|
244
|
+
# def initialize(attributes = {})
|
245
|
+
# @account = Account.new
|
246
|
+
# super(attributes)
|
247
|
+
# models << account
|
248
|
+
# end
|
249
|
+
#
|
250
|
+
# attribute :confirmation, :boolean, default: false
|
251
|
+
# validates :confirmation, presence: true
|
252
|
+
#
|
253
|
+
# private
|
254
|
+
#
|
255
|
+
# attr_reader :account
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# registration = AccountRegistration
|
259
|
+
# registration.valid?
|
260
|
+
# #=> false
|
261
|
+
#
|
262
|
+
# # In addition to the model's own validation error information (`confirmation`), also aggregates
|
263
|
+
# # error information for objects stored in `account` (`name`, `email`) when validation is performed.
|
264
|
+
#
|
265
|
+
# registration.errors.map { _1.attribute } #=> [:name, :email, :confirmation]
|
266
|
+
#
|
267
|
+
# @return [ActiveModel::Errors]
|
268
|
+
|
269
|
+
# @endgroup
|
270
|
+
|
271
|
+
# @group Persistences
|
272
|
+
|
273
|
+
# @!method save(**options)
|
274
|
+
# Save the models that exist in models.
|
275
|
+
# Returns false if any of the targets fail, true if all succeed.
|
276
|
+
#
|
277
|
+
# The save is performed within a single transaction.
|
278
|
+
#
|
279
|
+
# Only the `:validate` option takes effect as it is required internally.
|
280
|
+
# However, we do not recommend explicitly specifying `validate: false` to skip validation.
|
281
|
+
# Additionally, the `:context` option is not accepted.
|
282
|
+
# The need for such a value indicates that operations from multiple contexts are being processed.
|
283
|
+
# If the contexts differ, we recommend separating them into different model definitions.
|
284
|
+
#
|
285
|
+
# @params [Hash] Optional parameters.
|
286
|
+
# @option options [Boolean] :validate Whether to run validations.
|
287
|
+
# This option is intended for internal use only.
|
288
|
+
# Users should avoid explicitly passing <tt>validate: false</tt>,
|
289
|
+
# as skipping validations can lead to unexpected behavior.
|
290
|
+
# @return [Boolean] returns true on success, false on failure.
|
291
|
+
|
292
|
+
# @!method save!(**options)
|
293
|
+
# Behavior is same to {#save}, but raises an exception prematurely on failure.
|
294
|
+
# @see #save
|
295
|
+
# @raise ActiveRecord::RecordInvalid
|
296
|
+
# @raise ActiveRecord::RecordNotSaved
|
297
|
+
|
298
|
+
# @!method update(attributes)
|
299
|
+
# Assign attributes and {#save}.
|
300
|
+
#
|
301
|
+
# @param [Hash<String, Object>] attributes
|
302
|
+
# new attributes.
|
303
|
+
# @see #save
|
304
|
+
# @return [Boolean] returns true on success, false on failure.
|
305
|
+
|
306
|
+
# @!method update!(attributes)
|
307
|
+
# Behavior is same to {#update}, but raises an exception prematurely on failure.
|
308
|
+
#
|
309
|
+
# @param [Hash<String, Object>] attributes
|
310
|
+
# new attributes.
|
311
|
+
# @see #save
|
312
|
+
# @see #update
|
313
|
+
# @raise ActiveRecord::RecordInvalid
|
314
|
+
# @raise ActiveRecord::RecordNotSaved
|
315
|
+
|
316
|
+
# @endgroup
|
317
|
+
|
318
|
+
# @group Callbacks
|
319
|
+
|
320
|
+
# @!method self.before_save(*args, &block)
|
321
|
+
# Registers a callback to be called before a model is saved.
|
322
|
+
|
323
|
+
# @!method self.around_save(*args, &block)
|
324
|
+
# Registers a callback to be called around the save of a model.
|
325
|
+
|
326
|
+
# @!method self.after_save(*args, &block)
|
327
|
+
# Registers a callback to be called after a model is saved.
|
328
|
+
|
329
|
+
# @!method self.before_create(*args, &block)
|
330
|
+
# Registers a callback to be called before a model is created.
|
331
|
+
|
332
|
+
# @!method self.around_create(*args, &block)
|
333
|
+
# Registers a callback to be called around the creation of a model.
|
334
|
+
|
335
|
+
# @!method self.after_create(*args, &block)
|
336
|
+
# Registers a callback to be called after a model is created.
|
337
|
+
|
338
|
+
# @!method self.before_update(*args, &block)
|
339
|
+
# Registers a callback to be called before a model is updated.
|
340
|
+
|
341
|
+
# @!method self.around_update(*args, &block)
|
342
|
+
# Registers a callback to be called around the update of a model.
|
343
|
+
|
344
|
+
# @!method self.after_update(*args, &block)
|
345
|
+
# Registers a callback to be called after a update is updated.
|
346
|
+
|
347
|
+
# @!method self.after_commit(*args, &block)
|
348
|
+
# Registers a block to be called after the transaction is fully committed.
|
349
|
+
|
350
|
+
# @!method self.after_rollback(*args, &block)
|
351
|
+
# Registers a block to be called after the transaction is rolled back.
|
352
|
+
|
353
|
+
# @endgroup
|
354
|
+
end
|
355
|
+
|
356
|
+
# @group Model Core
|
21
357
|
|
22
358
|
def initialize(attributes = {})
|
23
359
|
super
|
24
360
|
end
|
25
361
|
|
26
|
-
# Returns true if model is persisted.
|
27
|
-
#
|
28
|
-
# By overriding this definition, you can control the callbacks that are triggered when a save is made.
|
29
|
-
# For example, returning false will trigger before_create, around_create and after_create,
|
30
|
-
# and returning true will trigger before_update, around_update and after_update.
|
31
|
-
#
|
32
|
-
# @return [Boolean] returns true if model is persisted.
|
33
|
-
def persisted? = super
|
34
|
-
|
35
362
|
private
|
36
363
|
|
364
|
+
# Returns a collection of model elements to encapsulate.
|
365
|
+
# @example Adding models
|
366
|
+
# models << inner_model_a << inner_model_b
|
367
|
+
# models.push(inner_model_c)
|
368
|
+
# @example `#push` can have `:destroy` `:if` options
|
369
|
+
# models.push(profile, destroy: :blank_profile?)
|
370
|
+
# models.push(profile, destroy: -> { blank_profile? })
|
371
|
+
# @return [ActiveRecordCompose::ComposedCollection]
|
372
|
+
#
|
37
373
|
def models = @__models ||= ActiveRecordCompose::ComposedCollection.new(self)
|
374
|
+
|
375
|
+
# @endgroup
|
38
376
|
end
|
39
377
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "callbacks"
|
3
4
|
require_relative "composed_collection"
|
4
5
|
|
5
6
|
module ActiveRecordCompose
|
6
7
|
using ComposedCollection::PackagePrivate
|
7
8
|
|
9
|
+
# @private
|
8
10
|
module Persistence
|
9
11
|
extend ActiveSupport::Concern
|
10
|
-
include ActiveRecordCompose::
|
12
|
+
include ActiveRecordCompose::Callbacks
|
11
13
|
|
12
14
|
# Save the models that exist in models.
|
13
15
|
# Returns false if any of the targets fail, true if all succeed.
|
@@ -22,11 +24,9 @@ module ActiveRecordCompose
|
|
22
24
|
#
|
23
25
|
# @return [Boolean] returns true on success, false on failure.
|
24
26
|
def save(**options)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
false
|
29
|
-
end
|
27
|
+
with_callbacks { save_models(**options, bang: false) }
|
28
|
+
rescue ActiveRecord::RecordInvalid
|
29
|
+
false
|
30
30
|
end
|
31
31
|
|
32
32
|
# Save the models that exist in models.
|
@@ -41,28 +41,22 @@ module ActiveRecordCompose
|
|
41
41
|
# If the contexts differ, we recommend separating them into different model definitions.
|
42
42
|
#
|
43
43
|
def save!(**options)
|
44
|
-
|
45
|
-
with_callbacks { save_models(**options, bang: true) }
|
46
|
-
end || raise_on_save_error
|
44
|
+
with_callbacks { save_models(**options, bang: true) } || raise_on_save_error
|
47
45
|
end
|
48
46
|
|
49
47
|
# Assign attributes and save.
|
50
48
|
#
|
51
49
|
# @return [Boolean] returns true on success, false on failure.
|
52
|
-
def update(attributes
|
53
|
-
|
54
|
-
|
55
|
-
save
|
56
|
-
end
|
50
|
+
def update(attributes)
|
51
|
+
assign_attributes(attributes)
|
52
|
+
save
|
57
53
|
end
|
58
54
|
|
59
55
|
# Behavior is same to `#update`, but raises an exception prematurely on failure.
|
60
56
|
#
|
61
|
-
def update!(attributes
|
62
|
-
|
63
|
-
|
64
|
-
save!
|
65
|
-
end
|
57
|
+
def update!(attributes)
|
58
|
+
assign_attributes(attributes)
|
59
|
+
save!
|
66
60
|
end
|
67
61
|
|
68
62
|
private
|
@@ -1,22 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveRecordCompose
|
4
|
+
# @private
|
4
5
|
module TransactionSupport
|
5
6
|
extend ActiveSupport::Concern
|
6
7
|
include ActiveRecord::Transactions
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
9
|
+
included do
|
10
|
+
# ActiveRecord::Transactions is defined so that methods such as save,
|
11
|
+
# destroy and touch are wrapped with_transaction_returning_status.
|
12
|
+
# However, ActiveRecordCompose::Model does not support destroy and touch, and
|
13
|
+
# we want to keep these operations as undefined behavior, so we remove the definition here.
|
14
|
+
undef_method :destroy, :touch
|
15
|
+
end
|
16
16
|
|
17
|
-
|
17
|
+
module ClassMethods
|
18
|
+
delegate :with_connection, :lease_connection, to: :ar_class
|
18
19
|
|
19
|
-
|
20
|
+
# In ActiveRecord, it is soft deprecated.
|
21
|
+
delegate :connection, to: :ar_class
|
20
22
|
|
21
23
|
def composite_primary_key? = false # steep:ignore
|
22
24
|
|
@@ -1,10 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "composed_collection"
|
4
|
+
|
3
5
|
module ActiveRecordCompose
|
4
6
|
using ComposedCollection::PackagePrivate
|
5
7
|
|
8
|
+
# @private
|
6
9
|
module Validations
|
7
10
|
extend ActiveSupport::Concern
|
11
|
+
include ActiveModel::Validations::Callbacks
|
8
12
|
|
9
13
|
included do
|
10
14
|
validate :validate_models
|
@@ -3,10 +3,12 @@
|
|
3
3
|
require "active_support/core_ext/object"
|
4
4
|
|
5
5
|
module ActiveRecordCompose
|
6
|
+
# @private
|
6
7
|
class WrappedModel
|
7
8
|
# @param model [Object] the model instance.
|
8
|
-
# @param destroy [Boolean]
|
9
|
-
#
|
9
|
+
# @param destroy [Boolean, Proc, Symbol] Controls whether the model should be destroyed.
|
10
|
+
# - Boolean: if `true`, the model will be destroyed.
|
11
|
+
# - Proc: the model will be destroyed if the proc returns `true`.
|
10
12
|
# @param if [Proc] evaluation result is false, it will not be included in the renewal.
|
11
13
|
def initialize(model, destroy: false, if: nil)
|
12
14
|
@model = model
|
@@ -5,5 +5,9 @@ require "active_record"
|
|
5
5
|
require_relative "active_record_compose/version"
|
6
6
|
require_relative "active_record_compose/model"
|
7
7
|
|
8
|
+
# namespaces in gem `active_record_compose`.
|
9
|
+
#
|
10
|
+
# Most of the functionality resides in {ActiveRecordCompose::Model}.
|
11
|
+
#
|
8
12
|
module ActiveRecordCompose
|
9
13
|
end
|
@@ -1,11 +1,57 @@
|
|
1
1
|
module ActiveRecordCompose
|
2
|
-
module
|
3
|
-
include ActiveModel::AttributeMethods
|
2
|
+
module Attributes
|
4
3
|
extend ActiveSupport::Concern
|
5
|
-
|
4
|
+
include ActiveModel::Attributes
|
5
|
+
include Querying
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
def delegated_attributes: () -> Array[Delegation]
|
8
|
+
|
9
|
+
module ClassMethods : Module
|
10
|
+
include ActiveModel::Attributes::ClassMethods
|
11
|
+
include ActiveModel::AttributeMethods::ClassMethods
|
12
|
+
|
13
|
+
def delegate_attribute: (*untyped methods, to: untyped, ?allow_nil: bool) -> untyped
|
14
|
+
def delegated_attributes: () -> Array[Delegation]
|
15
|
+
def delegated_attributes=: (Array[Delegation]) -> untyped
|
16
|
+
end
|
17
|
+
|
18
|
+
class AttributePredicate
|
19
|
+
def initialize: (untyped value) -> void
|
20
|
+
def call: -> bool
|
21
|
+
|
22
|
+
@value: untyped
|
23
|
+
|
24
|
+
private
|
25
|
+
attr_reader value: untyped
|
26
|
+
end
|
27
|
+
|
28
|
+
class Delegation
|
29
|
+
def initialize: (attribute: String, to: Symbol, ?allow_nil: bool) -> void
|
30
|
+
def attribute: () -> Symbol
|
31
|
+
def attribute_name: () -> String
|
32
|
+
def attribute_hash: (Object model) -> Hash[String, untyped]
|
33
|
+
def define_delegated_attribute: ((Module & ActiveModel::AttributeMethods::ClassMethods) klass) -> void
|
34
|
+
|
35
|
+
@attribute: Symbol
|
36
|
+
@to: Symbol
|
37
|
+
@allow_nil: bool
|
38
|
+
|
39
|
+
private
|
40
|
+
def to: () -> Symbol
|
41
|
+
def allow_nil: () -> bool
|
42
|
+
def reader: () -> String
|
43
|
+
def writer: () -> String
|
44
|
+
end
|
45
|
+
|
46
|
+
module Querying
|
47
|
+
include ActiveModel::AttributeMethods
|
48
|
+
extend ActiveSupport::Concern
|
49
|
+
extend ActiveModel::AttributeMethods::ClassMethods
|
50
|
+
|
51
|
+
private
|
52
|
+
def attribute?: (attribute_name) -> untyped
|
53
|
+
def query?: (untyped value) -> bool
|
54
|
+
end
|
9
55
|
end
|
10
56
|
|
11
57
|
module Callbacks
|
@@ -37,34 +83,9 @@ module ActiveRecordCompose
|
|
37
83
|
include PackagePrivate
|
38
84
|
end
|
39
85
|
|
40
|
-
module DelegateAttribute
|
41
|
-
include ActiveModel::Attributes
|
42
|
-
extend ActiveSupport::Concern
|
43
|
-
|
44
|
-
class Delegation
|
45
|
-
def initialize: (attribute: String, to: Symbol, allow_nil: boolish) -> void
|
46
|
-
def attribute: () -> String
|
47
|
-
def to: () -> Symbol
|
48
|
-
def allow_nil: () -> boolish
|
49
|
-
def reader: () -> String
|
50
|
-
def writer: () -> String
|
51
|
-
end
|
52
|
-
|
53
|
-
def delegated_attributes: () -> Array[Delegation]
|
54
|
-
|
55
|
-
module ClassMethods : Module
|
56
|
-
include ActiveModel::Attributes::ClassMethods
|
57
|
-
include ActiveModel::AttributeMethods::ClassMethods
|
58
|
-
|
59
|
-
def delegate_attribute: (*untyped methods, to: untyped, ?allow_nil: untyped?) -> untyped
|
60
|
-
def delegated_attributes: () -> Array[Delegation]
|
61
|
-
def delegated_attributes=: (Array[Delegation]) -> untyped
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
86
|
class Model
|
66
|
-
include
|
67
|
-
extend
|
87
|
+
include Attributes
|
88
|
+
extend Attributes::ClassMethods
|
68
89
|
include TransactionSupport
|
69
90
|
extend TransactionSupport::ClassMethods
|
70
91
|
include Callbacks
|
@@ -77,6 +98,7 @@ module ActiveRecordCompose
|
|
77
98
|
end
|
78
99
|
|
79
100
|
module TransactionSupport
|
101
|
+
extend ActiveSupport::Concern
|
80
102
|
include ActiveRecord::Transactions
|
81
103
|
|
82
104
|
def id: -> untyped
|
@@ -98,8 +120,8 @@ module ActiveRecordCompose
|
|
98
120
|
|
99
121
|
def save: (**untyped options) -> bool
|
100
122
|
def save!: (**untyped options) -> untyped
|
101
|
-
def update: (
|
102
|
-
def update!: (
|
123
|
+
def update: (Hash[attribute_name, untyped]) -> bool
|
124
|
+
def update!: (Hash[attribute_name, untyped]) -> untyped
|
103
125
|
|
104
126
|
private
|
105
127
|
def models: -> ComposedCollection
|
@@ -71,7 +71,7 @@ module ActiveRecordCompose
|
|
71
71
|
def self.after_commit: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
72
72
|
def self.after_rollback: (*callback[instance], ?if: condition[instance], ?unless: condition[instance], **untyped) ?{ () [self: instance] -> void } -> void
|
73
73
|
|
74
|
-
def self.delegate_attribute: (*untyped methods, to: untyped, ?allow_nil:
|
74
|
+
def self.delegate_attribute: (*untyped methods, to: untyped, ?allow_nil: bool) -> untyped
|
75
75
|
def self.connection: -> ActiveRecord::ConnectionAdapters::AbstractAdapter
|
76
76
|
def self.lease_connection: -> ActiveRecord::ConnectionAdapters::AbstractAdapter
|
77
77
|
def self.with_connection: [T] () { () -> T } -> T
|
@@ -79,14 +79,10 @@ module ActiveRecordCompose
|
|
79
79
|
def initialize: (?Hash[attribute_name, untyped]) -> void
|
80
80
|
def save: (**untyped options) -> bool
|
81
81
|
def save!: (**untyped options) -> untyped
|
82
|
-
def update: (
|
83
|
-
def update!: (
|
84
|
-
def id: -> untyped
|
82
|
+
def update: (Hash[attribute_name, untyped]) -> bool
|
83
|
+
def update!: (Hash[attribute_name, untyped]) -> untyped
|
85
84
|
|
86
85
|
private
|
87
86
|
def models: -> ComposedCollection
|
88
|
-
def save_models: (bang: bool, **untyped options) -> bool
|
89
|
-
def raise_on_save_error: -> bot
|
90
|
-
def raise_on_save_error_message: -> String
|
91
87
|
end
|
92
88
|
end
|