active_record_compose 0.11.3 → 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/CHANGELOG.md +12 -0
- data/lib/active_record_compose/attributes/attribute_predicate.rb +29 -0
- data/lib/active_record_compose/attributes/delegation.rb +7 -1
- data/lib/active_record_compose/attributes/querying.rb +5 -12
- data/lib/active_record_compose/attributes.rb +3 -29
- data/lib/active_record_compose/callbacks.rb +0 -4
- data/lib/active_record_compose/model.rb +4 -2
- data/lib/active_record_compose/persistence.rb +12 -20
- data/lib/active_record_compose/transaction_support.rb +11 -10
- data/lib/active_record_compose/validations.rb +1 -0
- data/lib/active_record_compose/version.rb +1 -1
- data/sig/_internal/package_private.rbs +14 -2
- data/sig/active_record_compose.rbs +2 -6
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 954ce34124a1c8e83a45710e104dd965c407afb5ba296b74d4a4e5f9d13d971a
|
4
|
+
data.tar.gz: c1bb35ef5458a804f243b886c037aff3794822477ea2aaf5a57bfb12a4001477
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e7f81f304cec10420cb4f405ad8ad7f93f3811c7f43bf9952c05dbca84e651bbf0c851e648349d7e93986cf67cb177110785588a47c8951718f4d271cf53944
|
7
|
+
data.tar.gz: 8ac490bd69c0d51e6e89f1f198a4e052eccbeedcf1b234edfa8c9635819fe336bbe10b6b64b6b55907524543ad34eb9343892b00f54f2737a65c45c120456afa
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.12.0] - 2025-08-21
|
4
|
+
|
5
|
+
- Omits default arguments for `#update` and `#update!`. It's to align I/F with ActiveRecord.
|
6
|
+
(https://github.com/hamajyotan/active_record_compose/pull/25)
|
7
|
+
- `#update(attributes = {})` to `#update(attributes)`
|
8
|
+
- `#update!(attributes = {})` to `#update!(attributes)`
|
9
|
+
- Omitted Specify instance variables in the `:to` option of `delegate_attribute`.
|
10
|
+
(https://github.com/hamajyotan/active_record_compose/pull/29)
|
11
|
+
- Omitted `#destroy` and `#touch` from `ActiveRecordCompose::Model`.
|
12
|
+
These were unintentionally provided by the `ActiveRecord::Transactions` module. The but in fact did not work correctly.
|
13
|
+
(https://github.com/hamajyotan/active_record_compose/pull/27)
|
14
|
+
|
3
15
|
## [0.11.3] - 2025-07-13
|
4
16
|
|
5
17
|
- refactor: Aggregation attribute module.
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecordCompose
|
4
|
+
module Attributes
|
5
|
+
# @private
|
6
|
+
class AttributePredicate
|
7
|
+
def initialize(value)
|
8
|
+
@value = value
|
9
|
+
end
|
10
|
+
|
11
|
+
def call
|
12
|
+
case value
|
13
|
+
when true then true
|
14
|
+
when false, nil then false
|
15
|
+
else
|
16
|
+
if value.respond_to?(:zero?)
|
17
|
+
!value.zero?
|
18
|
+
else
|
19
|
+
value.present?
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
attr_reader :value
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "attribute_predicate"
|
4
|
+
|
3
5
|
module ActiveRecordCompose
|
4
6
|
module Attributes
|
5
7
|
# @private
|
@@ -17,7 +19,11 @@ module ActiveRecordCompose
|
|
17
19
|
|
18
20
|
def define_delegated_attribute(klass)
|
19
21
|
klass.delegate(reader, writer, to:, allow_nil:)
|
20
|
-
klass.
|
22
|
+
klass.module_eval <<~RUBY, __FILE__, __LINE__ + 1
|
23
|
+
def #{reader}?
|
24
|
+
ActiveRecordCompose::Attributes::AttributePredicate.new(#{reader}).call
|
25
|
+
end
|
26
|
+
RUBY
|
21
27
|
end
|
22
28
|
|
23
29
|
# @return [String] The attribute name as string
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "attribute_predicate"
|
4
|
+
|
3
5
|
module ActiveRecordCompose
|
4
6
|
module Attributes
|
5
7
|
# @private
|
@@ -50,19 +52,10 @@ module ActiveRecordCompose
|
|
50
52
|
|
51
53
|
private
|
52
54
|
|
53
|
-
def attribute?(attr_name)
|
54
|
-
value = public_send(attr_name)
|
55
|
+
def attribute?(attr_name) = query?(public_send(attr_name))
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
when false, nil then false
|
59
|
-
else
|
60
|
-
if value.respond_to?(:zero?)
|
61
|
-
!value.zero?
|
62
|
-
else
|
63
|
-
value.present?
|
64
|
-
end
|
65
|
-
end
|
57
|
+
def query?(value)
|
58
|
+
ActiveRecordCompose::Attributes::AttributePredicate.new(value).call
|
66
59
|
end
|
67
60
|
end
|
68
61
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "attributes/attribute_predicate"
|
3
4
|
require_relative "attributes/delegation"
|
4
5
|
require_relative "attributes/querying"
|
5
6
|
|
@@ -62,9 +63,6 @@ module ActiveRecordCompose
|
|
62
63
|
end
|
63
64
|
|
64
65
|
module ClassMethods
|
65
|
-
ALLOW_NIL_DEFAULT = Object.new.freeze # steep:ignore
|
66
|
-
private_constant :ALLOW_NIL_DEFAULT
|
67
|
-
|
68
66
|
# Defines the reader and writer for the specified attribute.
|
69
67
|
#
|
70
68
|
# @example
|
@@ -97,34 +95,10 @@ module ActiveRecordCompose
|
|
97
95
|
# registration.attributes
|
98
96
|
# # => { "original_attribute" => "qux", "name" => "bar" }
|
99
97
|
#
|
100
|
-
def delegate_attribute(*attributes, to:, allow_nil:
|
101
|
-
# steep:ignore:start
|
98
|
+
def delegate_attribute(*attributes, to:, allow_nil: false)
|
102
99
|
if to.start_with?("@")
|
103
|
-
|
104
|
-
suggested_method =
|
105
|
-
if to.start_with?("@@")
|
106
|
-
"def #{suggested_reader_name} = #{to}"
|
107
|
-
else
|
108
|
-
"attr_reader :#{suggested_reader_name}"
|
109
|
-
end
|
110
|
-
|
111
|
-
message = <<~MSG
|
112
|
-
Direct use of instance or class variables in `to:` will be removed in the next minor version.
|
113
|
-
Please define a reader method (private is fine) and refer to it by name instead.
|
114
|
-
|
115
|
-
For example,
|
116
|
-
delegate_attribute #{attributes.map { ":#{_1}" }.join(", ")}, to: :#{to}#{", allow_nil: #{allow_nil}" if allow_nil != ALLOW_NIL_DEFAULT}
|
117
|
-
|
118
|
-
Instead of the above, use the following
|
119
|
-
delegate_attribute #{attributes.map { ":#{_1}" }.join(", ")}, to: :#{suggested_reader_name}#{", allow_nil: #{allow_nil}" if allow_nil != ALLOW_NIL_DEFAULT}
|
120
|
-
private
|
121
|
-
#{suggested_method}
|
122
|
-
|
123
|
-
MSG
|
124
|
-
(ActiveRecord.respond_to?(:deprecator) ? ActiveRecord.deprecator : ActiveSupport::Deprecation).warn(message)
|
100
|
+
raise ArgumentError, "Instance variables cannot be specified in delegate to. (#{to})"
|
125
101
|
end
|
126
|
-
allow_nil = false if allow_nil == ALLOW_NIL_DEFAULT
|
127
|
-
# steep:ignore:end
|
128
102
|
|
129
103
|
delegations = attributes.map { Delegation.new(attribute: _1, to:, allow_nil:) }
|
130
104
|
delegations.each { _1.define_delegated_attribute(self) }
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "validations"
|
4
|
-
|
5
3
|
module ActiveRecordCompose
|
6
4
|
# @private
|
7
5
|
#
|
@@ -23,8 +21,6 @@ module ActiveRecordCompose
|
|
23
21
|
include ActiveModel::Validations::Callbacks
|
24
22
|
|
25
23
|
included do
|
26
|
-
include ActiveRecordCompose::Validations
|
27
|
-
|
28
24
|
define_model_callbacks :save
|
29
25
|
define_model_callbacks :create
|
30
26
|
define_model_callbacks :update
|
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "attributes"
|
4
|
-
require_relative "callbacks"
|
5
4
|
require_relative "composed_collection"
|
6
5
|
require_relative "persistence"
|
6
|
+
require_relative "transaction_support"
|
7
|
+
require_relative "validations"
|
7
8
|
|
8
9
|
module ActiveRecordCompose
|
9
10
|
# This is the core class of {ActiveRecordCompose}.
|
@@ -83,7 +84,8 @@ module ActiveRecordCompose
|
|
83
84
|
|
84
85
|
include ActiveRecordCompose::Attributes
|
85
86
|
include ActiveRecordCompose::Persistence
|
86
|
-
include ActiveRecordCompose::
|
87
|
+
include ActiveRecordCompose::Validations
|
88
|
+
include ActiveRecordCompose::TransactionSupport
|
87
89
|
|
88
90
|
begin
|
89
91
|
# @group Model Core
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative "callbacks"
|
3
4
|
require_relative "composed_collection"
|
4
|
-
require_relative "transaction_support"
|
5
5
|
|
6
6
|
module ActiveRecordCompose
|
7
7
|
using ComposedCollection::PackagePrivate
|
@@ -9,7 +9,7 @@ module ActiveRecordCompose
|
|
9
9
|
# @private
|
10
10
|
module Persistence
|
11
11
|
extend ActiveSupport::Concern
|
12
|
-
include ActiveRecordCompose::
|
12
|
+
include ActiveRecordCompose::Callbacks
|
13
13
|
|
14
14
|
# Save the models that exist in models.
|
15
15
|
# Returns false if any of the targets fail, true if all succeed.
|
@@ -24,11 +24,9 @@ module ActiveRecordCompose
|
|
24
24
|
#
|
25
25
|
# @return [Boolean] returns true on success, false on failure.
|
26
26
|
def save(**options)
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
false
|
31
|
-
end
|
27
|
+
with_callbacks { save_models(**options, bang: false) }
|
28
|
+
rescue ActiveRecord::RecordInvalid
|
29
|
+
false
|
32
30
|
end
|
33
31
|
|
34
32
|
# Save the models that exist in models.
|
@@ -43,28 +41,22 @@ module ActiveRecordCompose
|
|
43
41
|
# If the contexts differ, we recommend separating them into different model definitions.
|
44
42
|
#
|
45
43
|
def save!(**options)
|
46
|
-
|
47
|
-
with_callbacks { save_models(**options, bang: true) }
|
48
|
-
end || raise_on_save_error
|
44
|
+
with_callbacks { save_models(**options, bang: true) } || raise_on_save_error
|
49
45
|
end
|
50
46
|
|
51
47
|
# Assign attributes and save.
|
52
48
|
#
|
53
49
|
# @return [Boolean] returns true on success, false on failure.
|
54
|
-
def update(attributes
|
55
|
-
|
56
|
-
|
57
|
-
save
|
58
|
-
end
|
50
|
+
def update(attributes)
|
51
|
+
assign_attributes(attributes)
|
52
|
+
save
|
59
53
|
end
|
60
54
|
|
61
55
|
# Behavior is same to `#update`, but raises an exception prematurely on failure.
|
62
56
|
#
|
63
|
-
def update!(attributes
|
64
|
-
|
65
|
-
|
66
|
-
save!
|
67
|
-
end
|
57
|
+
def update!(attributes)
|
58
|
+
assign_attributes(attributes)
|
59
|
+
save!
|
68
60
|
end
|
69
61
|
|
70
62
|
private
|
@@ -6,18 +6,19 @@ module ActiveRecordCompose
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
include ActiveRecord::Transactions
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
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
|
17
16
|
|
18
|
-
|
17
|
+
module ClassMethods
|
18
|
+
delegate :with_connection, :lease_connection, to: :ar_class
|
19
19
|
|
20
|
-
|
20
|
+
# In ActiveRecord, it is soft deprecated.
|
21
|
+
delegate :connection, to: :ar_class
|
21
22
|
|
22
23
|
def composite_primary_key? = false # steep:ignore
|
23
24
|
|
@@ -15,6 +15,16 @@ module ActiveRecordCompose
|
|
15
15
|
def delegated_attributes=: (Array[Delegation]) -> untyped
|
16
16
|
end
|
17
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
|
+
|
18
28
|
class Delegation
|
19
29
|
def initialize: (attribute: String, to: Symbol, ?allow_nil: bool) -> void
|
20
30
|
def attribute: () -> Symbol
|
@@ -40,6 +50,7 @@ module ActiveRecordCompose
|
|
40
50
|
|
41
51
|
private
|
42
52
|
def attribute?: (attribute_name) -> untyped
|
53
|
+
def query?: (untyped value) -> bool
|
43
54
|
end
|
44
55
|
end
|
45
56
|
|
@@ -87,6 +98,7 @@ module ActiveRecordCompose
|
|
87
98
|
end
|
88
99
|
|
89
100
|
module TransactionSupport
|
101
|
+
extend ActiveSupport::Concern
|
90
102
|
include ActiveRecord::Transactions
|
91
103
|
|
92
104
|
def id: -> untyped
|
@@ -108,8 +120,8 @@ module ActiveRecordCompose
|
|
108
120
|
|
109
121
|
def save: (**untyped options) -> bool
|
110
122
|
def save!: (**untyped options) -> untyped
|
111
|
-
def update: (
|
112
|
-
def update!: (
|
123
|
+
def update: (Hash[attribute_name, untyped]) -> bool
|
124
|
+
def update!: (Hash[attribute_name, untyped]) -> untyped
|
113
125
|
|
114
126
|
private
|
115
127
|
def models: -> ComposedCollection
|
@@ -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
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_record_compose
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.12.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- hamajyotan
|
@@ -45,6 +45,7 @@ files:
|
|
45
45
|
- README.md
|
46
46
|
- lib/active_record_compose.rb
|
47
47
|
- lib/active_record_compose/attributes.rb
|
48
|
+
- lib/active_record_compose/attributes/attribute_predicate.rb
|
48
49
|
- lib/active_record_compose/attributes/delegation.rb
|
49
50
|
- lib/active_record_compose/attributes/querying.rb
|
50
51
|
- lib/active_record_compose/callbacks.rb
|