dynamoid 3.10.0 → 3.11.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +182 -2
  4. data/dynamoid.gemspec +4 -4
  5. data/lib/dynamoid/adapter.rb +1 -1
  6. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/filter_expression_convertor.rb +53 -18
  7. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +5 -4
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/projection_expression_convertor.rb +9 -7
  9. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +1 -1
  10. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +1 -1
  11. data/lib/dynamoid/adapter_plugin/aws_sdk_v3/transact.rb +31 -0
  12. data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +9 -5
  13. data/lib/dynamoid/components.rb +1 -0
  14. data/lib/dynamoid/config.rb +2 -0
  15. data/lib/dynamoid/criteria/chain.rb +63 -18
  16. data/lib/dynamoid/criteria/where_conditions.rb +13 -6
  17. data/lib/dynamoid/dirty.rb +86 -11
  18. data/lib/dynamoid/dumping.rb +36 -14
  19. data/lib/dynamoid/errors.rb +14 -2
  20. data/lib/dynamoid/finders.rb +6 -6
  21. data/lib/dynamoid/loadable.rb +1 -0
  22. data/lib/dynamoid/persistence/inc.rb +6 -7
  23. data/lib/dynamoid/persistence/item_updater_with_casting_and_dumping.rb +36 -0
  24. data/lib/dynamoid/persistence/item_updater_with_dumping.rb +33 -0
  25. data/lib/dynamoid/persistence/save.rb +5 -2
  26. data/lib/dynamoid/persistence/update_fields.rb +5 -3
  27. data/lib/dynamoid/persistence/upsert.rb +5 -4
  28. data/lib/dynamoid/persistence.rb +38 -17
  29. data/lib/dynamoid/transaction_write/base.rb +47 -0
  30. data/lib/dynamoid/transaction_write/create.rb +49 -0
  31. data/lib/dynamoid/transaction_write/delete_with_instance.rb +60 -0
  32. data/lib/dynamoid/transaction_write/delete_with_primary_key.rb +59 -0
  33. data/lib/dynamoid/transaction_write/destroy.rb +79 -0
  34. data/lib/dynamoid/transaction_write/save.rb +164 -0
  35. data/lib/dynamoid/transaction_write/update_attributes.rb +46 -0
  36. data/lib/dynamoid/transaction_write/update_fields.rb +102 -0
  37. data/lib/dynamoid/transaction_write/upsert.rb +96 -0
  38. data/lib/dynamoid/transaction_write.rb +464 -0
  39. data/lib/dynamoid/type_casting.rb +3 -1
  40. data/lib/dynamoid/undumping.rb +13 -2
  41. data/lib/dynamoid/validations.rb +1 -1
  42. data/lib/dynamoid/version.rb +1 -1
  43. data/lib/dynamoid.rb +7 -0
  44. metadata +18 -5
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'item_updater_with_casting_and_dumping'
4
+
3
5
  module Dynamoid
4
6
  module Persistence
5
7
  # @private
@@ -32,11 +34,10 @@ module Dynamoid
32
34
 
33
35
  def update_item
34
36
  Dynamoid.adapter.update_item(@model_class.table_name, @partition_key, options_to_update_item) do |t|
35
- @attributes.each do |k, v|
36
- value_casted = TypeCasting.cast_field(v, @model_class.attributes[k])
37
- value_dumped = Dumping.dump_field(value_casted, @model_class.attributes[k])
37
+ item_updater = ItemUpdaterWithCastingAndDumping.new(@model_class, t)
38
38
 
39
- t.set(k => value_dumped)
39
+ @attributes.each do |k, v|
40
+ item_updater.set(k => v)
40
41
  end
41
42
  end
42
43
  end
@@ -10,6 +10,7 @@ require 'dynamoid/persistence/upsert'
10
10
  require 'dynamoid/persistence/save'
11
11
  require 'dynamoid/persistence/inc'
12
12
  require 'dynamoid/persistence/update_validations'
13
+ require 'dynamoid/persistence/item_updater_with_dumping'
13
14
 
14
15
  # encoding: utf-8
15
16
  module Dynamoid
@@ -18,8 +19,9 @@ module Dynamoid
18
19
  module Persistence
19
20
  extend ActiveSupport::Concern
20
21
 
21
- attr_accessor :new_record
22
+ attr_accessor :new_record, :destroyed
22
23
  alias new_record? new_record
24
+ alias destroyed? destroyed
23
25
 
24
26
  # @private
25
27
  UNIX_EPOCH_DATE = Date.new(1970, 1, 1).freeze
@@ -166,7 +168,7 @@ module Dynamoid
166
168
 
167
169
  # Create a model.
168
170
  #
169
- # Initializes a new model and immediately saves it to DynamoDB.
171
+ # Initializes a new model and immediately saves it into DynamoDB.
170
172
  #
171
173
  # User.create(first_name: 'Mark', last_name: 'Tyler')
172
174
  #
@@ -174,7 +176,8 @@ module Dynamoid
174
176
  #
175
177
  # User.create([{ first_name: 'Alice' }, { first_name: 'Bob' }])
176
178
  #
177
- # Creates a model and pass it into a block to set other attributes.
179
+ # Instantiates a model and pass it into an optional block to set other
180
+ # attributes.
178
181
  #
179
182
  # User.create(first_name: 'Mark') do |u|
180
183
  # u.age = 21
@@ -182,7 +185,7 @@ module Dynamoid
182
185
  #
183
186
  # Validates model and runs callbacks.
184
187
  #
185
- # @param attrs [Hash|Array[Hash]] Attributes of the models
188
+ # @param attrs [Hash|Array<Hash>] Attributes of a model
186
189
  # @param block [Proc] Block to process a document after initialization
187
190
  # @return [Dynamoid::Document] The created document
188
191
  # @since 0.2.0
@@ -196,12 +199,28 @@ module Dynamoid
196
199
 
197
200
  # Create a model.
198
201
  #
199
- # Initializes a new object and immediately saves it to the Dynamoid.
202
+ # Initializes a new object and immediately saves it into DynamoDB.
203
+ #
204
+ # User.create!(first_name: 'Mark', last_name: 'Tyler')
205
+ #
200
206
  # Raises an exception +Dynamoid::Errors::DocumentNotValid+ if validation
201
- # failed. Accepts both Hash and Array of Hashes and can create several
207
+ # failed.
208
+ #
209
+ # Accepts both Hash and Array of Hashes and can create several
202
210
  # models.
203
211
  #
204
- # @param attrs [Hash|Array[Hash]] Attributes with which to create the object.
212
+ # User.create!([{ first_name: 'Alice' }, { first_name: 'Bob' }])
213
+ #
214
+ # Instantiates a model and pass it into an optional block to set other
215
+ # attributes.
216
+ #
217
+ # User.create!(first_name: 'Mark') do |u|
218
+ # u.age = 21
219
+ # end
220
+ #
221
+ # Validates model and runs callbacks.
222
+ #
223
+ # @param attrs [Hash|Array<Hash>] Attributes with which to create the object.
205
224
  # @param block [Proc] Block to process a document after initialization
206
225
  # @return [Dynamoid::Document] The created document
207
226
  # @since 0.2.0
@@ -348,7 +367,7 @@ module Dynamoid
348
367
  # an updated document back with one HTTP request.
349
368
  #
350
369
  # Raises a +Dynamoid::Errors::UnknownAttribute+ exception if any of the
351
- # attributes is not on the model
370
+ # attributes is not declared in the model class.
352
371
  #
353
372
  # @param hash_key_value [Scalar value] hash key
354
373
  # @param range_key_value [Scalar value] range key (optional)
@@ -404,7 +423,7 @@ module Dynamoid
404
423
  # @param hash_key_value [Scalar value] hash key
405
424
  # @param range_key_value [Scalar value] range key (optional)
406
425
  # @param counters [Hash] value to increase by
407
- # @option counters [true | Symbol | Array[Symbol]] :touch to update update_at attribute and optionally the specified ones
426
+ # @option counters [true | Symbol | Array<Symbol>] :touch to update update_at attribute and optionally the specified ones
408
427
  # @return [Model class] self
409
428
  def inc(hash_key_value, range_key_value = nil, counters)
410
429
  Inc.call(self, hash_key_value, range_key_value, counters)
@@ -490,7 +509,7 @@ module Dynamoid
490
509
  #
491
510
  # +save+ by default sets timestamps attributes - +created_at+ and
492
511
  # +updated_at+ when creates new model and updates +updated_at+ attribute
493
- # when update already existing one.
512
+ # when updates already existing one.
494
513
  #
495
514
  # Changing +updated_at+ attribute at updating a model can be skipped with
496
515
  # +touch: false+ option:
@@ -535,7 +554,9 @@ module Dynamoid
535
554
  end
536
555
 
537
556
  # Update multiple attributes at once, saving the object once the updates
538
- # are complete. Returns +true+ if saving is successful and +false+
557
+ # are complete.
558
+ #
559
+ # Returns +true+ if saving is successful and +false+
539
560
  # otherwise.
540
561
  #
541
562
  # user.update_attributes(age: 27, last_name: 'Tylor')
@@ -668,12 +689,12 @@ module Dynamoid
668
689
  update_item_options = options.merge(conditions: conditions)
669
690
 
670
691
  new_attrs = Dynamoid.adapter.update_item(table_name, hash_key, update_item_options) do |t|
671
- t.add(lock_version: 1) if self.class.attributes[:lock_version]
692
+ item_updater = ItemUpdaterWithDumping.new(self.class, t)
693
+
694
+ item_updater.add(lock_version: 1) if self.class.attributes[:lock_version]
672
695
 
673
696
  if self.class.timestamps_enabled?
674
- time_now = DateTime.now.in_time_zone(Time.zone)
675
- time_now_dumped = Dumping.dump_field(time_now, self.class.attributes[:updated_at])
676
- t.set(updated_at: time_now_dumped)
697
+ item_updater.set(updated_at: DateTime.now.in_time_zone(Time.zone))
677
698
  end
678
699
 
679
700
  yield t
@@ -804,7 +825,7 @@ module Dynamoid
804
825
  #
805
826
  # @param attribute [Symbol] attribute name
806
827
  # @param by [Numeric] value to add (optional)
807
- # @param touch [true | Symbol | Array[Symbol]] to update update_at attribute and optionally the specified ones
828
+ # @param touch [true | Symbol | Array<Symbol>] to update update_at attribute and optionally the specified ones
808
829
  # @return [Dynamoid::Document] self
809
830
  def increment!(attribute, by = 1, touch: nil)
810
831
  increment(attribute, by)
@@ -855,7 +876,7 @@ module Dynamoid
855
876
  #
856
877
  # @param attribute [Symbol] attribute name
857
878
  # @param by [Numeric] value to subtract (optional)
858
- # @param touch [true | Symbol | Array[Symbol]] to update update_at attribute and optionally the specified ones
879
+ # @param touch [true | Symbol | Array<Symbol>] to update update_at attribute and optionally the specified ones
859
880
  # @return [Dynamoid::Document] self
860
881
  def decrement!(attribute, by = 1, touch: nil)
861
882
  increment!(attribute, -by, touch: touch)
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dynamoid
4
+ class TransactionWrite
5
+ class Base
6
+ # Callback called at "initialization" or "registration" an action
7
+ # before changes are persisted. It's a proper place to validate
8
+ # a model or run callbacks
9
+ def on_registration
10
+ raise 'Not implemented'
11
+ end
12
+
13
+ # Callback called after changes are persisted.
14
+ # It's a proper place to mark changes in a model as applied.
15
+ def on_commit
16
+ raise 'Not implemented'
17
+ end
18
+
19
+ # Callback called when a transaction is rolled back.
20
+ # It's a proper place to undo changes made in after_... callbacks.
21
+ def on_rollback
22
+ raise 'Not implemented'
23
+ end
24
+
25
+ # Whether some callback aborted or canceled an action
26
+ def aborted?
27
+ raise 'Not implemented'
28
+ end
29
+
30
+ # Whether there are changes to persist, e.g. updating a model with no
31
+ # attribute changed is skipped.
32
+ def skipped?
33
+ raise 'Not implemented'
34
+ end
35
+
36
+ # Value returned to a user as an action result
37
+ def observable_by_user_result
38
+ raise 'Not implemented'
39
+ end
40
+
41
+ # Coresponding part of a final request body
42
+ def action_request
43
+ raise 'Not implemented'
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Dynamoid
6
+ class TransactionWrite
7
+ class Create < Base
8
+ def initialize(model_class, attributes = {}, **options, &block)
9
+ super()
10
+
11
+ @model = model_class.new(attributes)
12
+
13
+ if block
14
+ yield(@model)
15
+ end
16
+
17
+ @save_action = Save.new(@model, **options)
18
+ end
19
+
20
+ def on_registration
21
+ @save_action.on_registration
22
+ end
23
+
24
+ def on_commit
25
+ @save_action.on_commit
26
+ end
27
+
28
+ def on_rollback
29
+ @save_action.on_rollback
30
+ end
31
+
32
+ def aborted?
33
+ @save_action.aborted?
34
+ end
35
+
36
+ def skipped?
37
+ false
38
+ end
39
+
40
+ def observable_by_user_result
41
+ @model
42
+ end
43
+
44
+ def action_request
45
+ @save_action.action_request
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Dynamoid
6
+ class TransactionWrite
7
+ class DeleteWithInstance < Base
8
+ def initialize(model)
9
+ super()
10
+
11
+ @model = model
12
+ @model_class = model.class
13
+ end
14
+
15
+ def on_registration
16
+ validate_model!
17
+ end
18
+
19
+ def on_commit
20
+ @model.destroyed = true
21
+ end
22
+
23
+ def on_rollback; end
24
+
25
+ def aborted?
26
+ false
27
+ end
28
+
29
+ def skipped?
30
+ false
31
+ end
32
+
33
+ def observable_by_user_result
34
+ @model
35
+ end
36
+
37
+ def action_request
38
+ key = { @model_class.hash_key => @model.hash_key }
39
+
40
+ if @model_class.range_key?
41
+ key[@model_class.range_key] = @model.range_value
42
+ end
43
+
44
+ {
45
+ delete: {
46
+ key: key,
47
+ table_name: @model_class.table_name
48
+ }
49
+ }
50
+ end
51
+
52
+ private
53
+
54
+ def validate_model!
55
+ raise Dynamoid::Errors::MissingHashKey if @model.hash_key.nil?
56
+ raise Dynamoid::Errors::MissingRangeKey if @model_class.range_key? && @model.range_value.nil?
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Dynamoid
6
+ class TransactionWrite
7
+ class DeleteWithPrimaryKey < Base
8
+ def initialize(model_class, hash_key, range_key)
9
+ super()
10
+
11
+ @model_class = model_class
12
+ @hash_key = hash_key
13
+ @range_key = range_key
14
+ end
15
+
16
+ def on_registration
17
+ validate_primary_key!
18
+ end
19
+
20
+ def on_commit; end
21
+
22
+ def on_rollback; end
23
+
24
+ def aborted?
25
+ false
26
+ end
27
+
28
+ def skipped?
29
+ false
30
+ end
31
+
32
+ def observable_by_user_result
33
+ nil
34
+ end
35
+
36
+ def action_request
37
+ key = { @model_class.hash_key => @hash_key }
38
+
39
+ if @model_class.range_key?
40
+ key[@model_class.range_key] = @range_key
41
+ end
42
+
43
+ {
44
+ delete: {
45
+ key: key,
46
+ table_name: @model_class.table_name
47
+ }
48
+ }
49
+ end
50
+
51
+ private
52
+
53
+ def validate_primary_key!
54
+ raise Dynamoid::Errors::MissingHashKey if @hash_key.nil?
55
+ raise Dynamoid::Errors::MissingRangeKey if @model_class.range_key? && @range_key.nil?
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Dynamoid
6
+ class TransactionWrite
7
+ class Destroy < Base
8
+ def initialize(model, **options)
9
+ super()
10
+
11
+ @model = model
12
+ @options = options
13
+ @model_class = model.class
14
+ @aborted = false
15
+ end
16
+
17
+ def on_registration
18
+ validate_model!
19
+
20
+ @aborted = true
21
+ @model.run_callbacks(:destroy) do
22
+ @aborted = false
23
+ true
24
+ end
25
+
26
+ if @aborted && @options[:raise_error]
27
+ raise Dynamoid::Errors::RecordNotDestroyed, @model
28
+ end
29
+ end
30
+
31
+ def on_commit
32
+ return if @aborted
33
+
34
+ @model.destroyed = true
35
+ @model.run_callbacks(:commit)
36
+ end
37
+
38
+ def on_rollback
39
+ @model.run_callbacks(:rollback)
40
+ end
41
+
42
+ def aborted?
43
+ @aborted
44
+ end
45
+
46
+ def skipped?
47
+ false
48
+ end
49
+
50
+ def observable_by_user_result
51
+ return false if @aborted
52
+
53
+ @model
54
+ end
55
+
56
+ def action_request
57
+ key = { @model_class.hash_key => @model.hash_key }
58
+
59
+ if @model_class.range_key?
60
+ key[@model_class.range_key] = @model.range_value
61
+ end
62
+
63
+ {
64
+ delete: {
65
+ key: key,
66
+ table_name: @model_class.table_name
67
+ }
68
+ }
69
+ end
70
+
71
+ private
72
+
73
+ def validate_model!
74
+ raise Dynamoid::Errors::MissingHashKey if @model.hash_key.nil?
75
+ raise Dynamoid::Errors::MissingRangeKey if @model_class.range_key? && @model.range_value.nil?
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module Dynamoid
6
+ class TransactionWrite
7
+ class Save < Base
8
+ def initialize(model, **options)
9
+ super()
10
+
11
+ @model = model
12
+ @model_class = model.class
13
+ @options = options
14
+
15
+ @aborted = false
16
+ @was_new_record = model.new_record?
17
+ @valid = nil
18
+ end
19
+
20
+ def on_registration
21
+ validate_model!
22
+
23
+ if @options[:validate] != false && !(@valid = @model.valid?)
24
+ if @options[:raise_error]
25
+ raise Dynamoid::Errors::DocumentNotValid, @model
26
+ else
27
+ @aborted = true
28
+ return
29
+ end
30
+ end
31
+
32
+ @aborted = true
33
+ callback_name = @was_new_record ? :create : :update
34
+
35
+ @model.run_callbacks(:save) do
36
+ @model.run_callbacks(callback_name) do
37
+ @model.run_callbacks(:validate) do
38
+ @aborted = false
39
+ true
40
+ end
41
+ end
42
+ end
43
+
44
+ if @aborted && @options[:raise_error]
45
+ raise Dynamoid::Errors::RecordNotSaved, @model
46
+ end
47
+
48
+ if @was_new_record && @model.hash_key.nil?
49
+ @model.hash_key = SecureRandom.uuid
50
+ end
51
+ end
52
+
53
+ def on_commit
54
+ return if @aborted
55
+
56
+ @model.changes_applied
57
+
58
+ if @was_new_record
59
+ @model.new_record = false
60
+ end
61
+
62
+ @model.run_callbacks(:commit)
63
+ end
64
+
65
+ def on_rollback
66
+ @model.run_callbacks(:rollback)
67
+ end
68
+
69
+ def aborted?
70
+ @aborted
71
+ end
72
+
73
+ def skipped?
74
+ @model.persisted? && !@model.changed?
75
+ end
76
+
77
+ def observable_by_user_result
78
+ !@aborted
79
+ end
80
+
81
+ def action_request
82
+ if @was_new_record
83
+ action_request_to_create
84
+ else
85
+ action_request_to_update
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ def validate_model!
92
+ raise Dynamoid::Errors::MissingHashKey if !@was_new_record && @model.hash_key.nil?
93
+ raise Dynamoid::Errors::MissingRangeKey if @model_class.range_key? && @model.range_value.nil?
94
+ end
95
+
96
+ def action_request_to_create
97
+ touch_model_timestamps(skip_created_at: false)
98
+
99
+ attributes_dumped = Dynamoid::Dumping.dump_attributes(@model.attributes, @model_class.attributes)
100
+
101
+ # require primary key not to exist yet
102
+ condition = "attribute_not_exists(#{@model_class.hash_key})"
103
+ if @model_class.range_key?
104
+ condition += " AND attribute_not_exists(#{@model_class.range_key})"
105
+ end
106
+
107
+ {
108
+ put: {
109
+ item: attributes_dumped,
110
+ table_name: @model_class.table_name,
111
+ condition_expression: condition
112
+ }
113
+ }
114
+ end
115
+
116
+ def action_request_to_update
117
+ touch_model_timestamps(skip_created_at: true)
118
+
119
+ # changed attributes to persist
120
+ changes = @model.attributes.slice(*@model.changed.map(&:to_sym))
121
+ changes_dumped = Dynamoid::Dumping.dump_attributes(changes, @model_class.attributes)
122
+
123
+ # primary key to look up an item to update
124
+ key = { @model_class.hash_key => @model.hash_key }
125
+ key[@model_class.range_key] = @model.range_value if @model_class.range_key?
126
+
127
+ # Build UpdateExpression and keep names and values placeholders mapping
128
+ # in ExpressionAttributeNames and ExpressionAttributeValues.
129
+ update_expression_statements = []
130
+ expression_attribute_names = {}
131
+ expression_attribute_values = {}
132
+
133
+ changes_dumped.each_with_index do |(name, value), i|
134
+ name_placeholder = "#_n#{i}"
135
+ value_placeholder = ":_s#{i}"
136
+
137
+ update_expression_statements << "#{name_placeholder} = #{value_placeholder}"
138
+ expression_attribute_names[name_placeholder] = name
139
+ expression_attribute_values[value_placeholder] = value
140
+ end
141
+
142
+ update_expression = "SET #{update_expression_statements.join(', ')}"
143
+
144
+ {
145
+ update: {
146
+ key: key,
147
+ table_name: @model_class.table_name,
148
+ update_expression: update_expression,
149
+ expression_attribute_names: expression_attribute_names,
150
+ expression_attribute_values: expression_attribute_values
151
+ }
152
+ }
153
+ end
154
+
155
+ def touch_model_timestamps(skip_created_at:)
156
+ return unless @model_class.timestamps_enabled?
157
+
158
+ timestamp = DateTime.now.in_time_zone(Time.zone)
159
+ @model.updated_at = timestamp unless @options[:touch] == false && !@was_new_record
160
+ @model.created_at ||= timestamp unless skip_created_at
161
+ end
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+ require 'dynamoid/persistence/update_validations'
5
+
6
+ module Dynamoid
7
+ class TransactionWrite
8
+ class UpdateAttributes < Base
9
+ def initialize(model, attributes, **options)
10
+ super()
11
+
12
+ @model = model
13
+ @model.assign_attributes(attributes)
14
+ @save_action = Save.new(model, **options)
15
+ end
16
+
17
+ def on_registration
18
+ @save_action.on_registration
19
+ end
20
+
21
+ def on_commit
22
+ @save_action.on_commit
23
+ end
24
+
25
+ def on_rollback
26
+ @save_action.on_rollback
27
+ end
28
+
29
+ def aborted?
30
+ @save_action.aborted?
31
+ end
32
+
33
+ def skipped?
34
+ @save_action.skipped?
35
+ end
36
+
37
+ def observable_by_user_result
38
+ @save_action.observable_by_user_result
39
+ end
40
+
41
+ def action_request
42
+ @save_action.action_request
43
+ end
44
+ end
45
+ end
46
+ end