dynamoid 3.9.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -6
- data/README.md +202 -25
- data/dynamoid.gemspec +5 -6
- data/lib/dynamoid/adapter.rb +19 -13
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +2 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/filter_expression_convertor.rb +113 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +21 -2
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/projection_expression_convertor.rb +40 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +46 -61
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +34 -28
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/transact.rb +31 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +95 -66
- data/lib/dynamoid/associations/belongs_to.rb +6 -6
- data/lib/dynamoid/associations.rb +1 -1
- data/lib/dynamoid/components.rb +1 -0
- data/lib/dynamoid/config/options.rb +12 -12
- data/lib/dynamoid/config.rb +3 -0
- data/lib/dynamoid/criteria/chain.rb +149 -142
- data/lib/dynamoid/criteria/key_fields_detector.rb +6 -7
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +2 -2
- data/lib/dynamoid/criteria/where_conditions.rb +36 -0
- data/lib/dynamoid/dirty.rb +87 -12
- data/lib/dynamoid/document.rb +1 -1
- data/lib/dynamoid/dumping.rb +38 -16
- data/lib/dynamoid/errors.rb +14 -2
- data/lib/dynamoid/fields/declare.rb +6 -6
- data/lib/dynamoid/fields.rb +6 -8
- data/lib/dynamoid/finders.rb +23 -32
- data/lib/dynamoid/indexes.rb +6 -7
- data/lib/dynamoid/loadable.rb +3 -2
- data/lib/dynamoid/persistence/inc.rb +6 -7
- data/lib/dynamoid/persistence/item_updater_with_casting_and_dumping.rb +36 -0
- data/lib/dynamoid/persistence/item_updater_with_dumping.rb +33 -0
- data/lib/dynamoid/persistence/save.rb +17 -18
- data/lib/dynamoid/persistence/update_fields.rb +7 -5
- data/lib/dynamoid/persistence/update_validations.rb +1 -1
- data/lib/dynamoid/persistence/upsert.rb +5 -4
- data/lib/dynamoid/persistence.rb +77 -21
- data/lib/dynamoid/transaction_write/base.rb +47 -0
- data/lib/dynamoid/transaction_write/create.rb +49 -0
- data/lib/dynamoid/transaction_write/delete_with_instance.rb +60 -0
- data/lib/dynamoid/transaction_write/delete_with_primary_key.rb +59 -0
- data/lib/dynamoid/transaction_write/destroy.rb +79 -0
- data/lib/dynamoid/transaction_write/save.rb +164 -0
- data/lib/dynamoid/transaction_write/update_attributes.rb +46 -0
- data/lib/dynamoid/transaction_write/update_fields.rb +102 -0
- data/lib/dynamoid/transaction_write/upsert.rb +96 -0
- data/lib/dynamoid/transaction_write.rb +464 -0
- data/lib/dynamoid/type_casting.rb +18 -15
- data/lib/dynamoid/undumping.rb +14 -3
- data/lib/dynamoid/validations.rb +1 -1
- data/lib/dynamoid/version.rb +1 -1
- data/lib/dynamoid.rb +7 -0
- metadata +30 -16
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +0 -41
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +0 -40
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dynamoid
|
4
|
+
module Persistence
|
5
|
+
# @private
|
6
|
+
class ItemUpdaterWithDumping
|
7
|
+
def initialize(model_class, item_updater)
|
8
|
+
@model_class = model_class
|
9
|
+
@item_updater = item_updater
|
10
|
+
end
|
11
|
+
|
12
|
+
def add(attributes)
|
13
|
+
@item_updater.add(dump(attributes))
|
14
|
+
end
|
15
|
+
|
16
|
+
def set(attributes)
|
17
|
+
@item_updater.set(dump(attributes))
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def dump(attributes)
|
23
|
+
dumped = {}
|
24
|
+
|
25
|
+
attributes.each do |name, value|
|
26
|
+
dumped[name] = Dumping.dump_field(value, @model_class.attributes[name])
|
27
|
+
end
|
28
|
+
|
29
|
+
dumped
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'item_updater_with_dumping'
|
4
|
+
|
3
5
|
module Dynamoid
|
4
6
|
module Persistence
|
5
7
|
# @private
|
@@ -36,9 +38,10 @@ module Dynamoid
|
|
36
38
|
attributes_to_persist = @model.attributes.slice(*@model.changed.map(&:to_sym))
|
37
39
|
|
38
40
|
Dynamoid.adapter.update_item(@model.class.table_name, @model.hash_key, options_to_update_item) do |t|
|
41
|
+
item_updater = ItemUpdaterWithDumping.new(@model.class, t)
|
42
|
+
|
39
43
|
attributes_to_persist.each do |name, value|
|
40
|
-
|
41
|
-
t.set(name => value_dumped)
|
44
|
+
item_updater.set(name => value)
|
42
45
|
end
|
43
46
|
end
|
44
47
|
end
|
@@ -68,13 +71,11 @@ module Dynamoid
|
|
68
71
|
end
|
69
72
|
|
70
73
|
# Add an optimistic locking check if the lock_version column exists
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
conditions[:if][:lock_version] = @model.changes[:lock_version][0]
|
77
|
-
end
|
74
|
+
# Uses the original lock_version value from Dirty API
|
75
|
+
# in case user changed 'lock_version' manually
|
76
|
+
if @model.class.attributes[:lock_version] && (@model.changes[:lock_version][0])
|
77
|
+
conditions[:if] ||= {}
|
78
|
+
conditions[:if][:lock_version] = @model.changes[:lock_version][0]
|
78
79
|
end
|
79
80
|
|
80
81
|
conditions
|
@@ -89,17 +90,15 @@ module Dynamoid
|
|
89
90
|
end
|
90
91
|
|
91
92
|
conditions = {}
|
92
|
-
conditions[:
|
93
|
-
conditions[:
|
93
|
+
conditions[:if] ||= {}
|
94
|
+
conditions[:if][@model.class.hash_key] = @model.hash_key
|
94
95
|
|
95
96
|
# Add an optimistic locking check if the lock_version column exists
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
conditions[:if][:lock_version] = @model.changes[:lock_version][0]
|
102
|
-
end
|
97
|
+
# Uses the original lock_version value from Dirty API
|
98
|
+
# in case user changed 'lock_version' manually
|
99
|
+
if @model.class.attributes[:lock_version] && (@model.changes[:lock_version][0])
|
100
|
+
conditions[:if] ||= {}
|
101
|
+
conditions[:if][:lock_version] = @model.changes[:lock_version][0]
|
103
102
|
end
|
104
103
|
|
105
104
|
options[:conditions] = conditions
|
@@ -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,10 +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|
|
37
|
+
item_updater = ItemUpdaterWithCastingAndDumping.new(@model_class, t)
|
38
|
+
|
35
39
|
@attributes.each do |k, v|
|
36
|
-
|
37
|
-
value_dumped = Dumping.dump_field(value_casted, @model_class.attributes[k])
|
38
|
-
t.set(k => value_dumped)
|
40
|
+
item_updater.set(k => v)
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -54,8 +56,8 @@ module Dynamoid
|
|
54
56
|
end
|
55
57
|
|
56
58
|
conditions = @conditions.deep_dup
|
57
|
-
conditions[:
|
58
|
-
conditions[:
|
59
|
+
conditions[:if] ||= {}
|
60
|
+
conditions[:if][@model_class.hash_key] = @partition_key
|
59
61
|
options[:conditions] = conditions
|
60
62
|
|
61
63
|
options
|
@@ -7,7 +7,7 @@ module Dynamoid
|
|
7
7
|
def self.validate_attributes_exist(model_class, attributes)
|
8
8
|
model_attributes = model_class.attributes.keys
|
9
9
|
|
10
|
-
attributes.
|
10
|
+
attributes.each_key do |attr_name|
|
11
11
|
unless model_attributes.include?(attr_name)
|
12
12
|
raise Dynamoid::Errors::UnknownAttribute, "Attribute #{attr_name} does not exist in #{model_class}"
|
13
13
|
end
|
@@ -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
|
-
|
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
|
-
|
39
|
+
@attributes.each do |k, v|
|
40
|
+
item_updater.set(k => v)
|
40
41
|
end
|
41
42
|
end
|
42
43
|
end
|
data/lib/dynamoid/persistence.rb
CHANGED
@@ -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
|
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
|
-
#
|
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
|
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
|
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.
|
207
|
+
# failed.
|
208
|
+
#
|
209
|
+
# Accepts both Hash and Array of Hashes and can create several
|
202
210
|
# models.
|
203
211
|
#
|
204
|
-
#
|
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
|
@@ -271,7 +290,7 @@ module Dynamoid
|
|
271
290
|
# meets the specified conditions. Conditions can be specified as a +Hash+
|
272
291
|
# with +:if+ key:
|
273
292
|
#
|
274
|
-
# User.update_fields('1', { age: 26 }, if: { version: 1 })
|
293
|
+
# User.update_fields('1', { age: 26 }, { if: { version: 1 } })
|
275
294
|
#
|
276
295
|
# Here +User+ model has an integer +version+ field and the document will
|
277
296
|
# be updated only if the +version+ attribute currently has value 1.
|
@@ -279,6 +298,13 @@ module Dynamoid
|
|
279
298
|
# If a document with specified hash and range keys doesn't exist or
|
280
299
|
# conditions were specified and failed the method call returns +nil+.
|
281
300
|
#
|
301
|
+
# To check if some attribute (or attributes) isn't stored in a DynamoDB
|
302
|
+
# item (e.g. it wasn't set explicitly) there is another condition -
|
303
|
+
# +unless_exists+:
|
304
|
+
#
|
305
|
+
# user = User.create(name: 'Tylor')
|
306
|
+
# User.update_fields(user.id, { age: 18 }, { unless_exists: [:age] })
|
307
|
+
#
|
282
308
|
# +update_fields+ uses the +UpdateItem+ operation so it saves changes and
|
283
309
|
# loads an updated document back with one HTTP request.
|
284
310
|
#
|
@@ -323,18 +349,25 @@ module Dynamoid
|
|
323
349
|
# meets the specified conditions. Conditions can be specified as a +Hash+
|
324
350
|
# with +:if+ key:
|
325
351
|
#
|
326
|
-
# User.upsert('1', { age: 26 }, if: { version: 1 })
|
352
|
+
# User.upsert('1', { age: 26 }, { if: { version: 1 } })
|
327
353
|
#
|
328
354
|
# Here +User+ model has an integer +version+ field and the document will
|
329
355
|
# be updated only if the +version+ attribute currently has value 1.
|
330
356
|
#
|
357
|
+
# To check if some attribute (or attributes) isn't stored in a DynamoDB
|
358
|
+
# item (e.g. it wasn't set explicitly) there is another condition -
|
359
|
+
# +unless_exists+:
|
360
|
+
#
|
361
|
+
# user = User.create(name: 'Tylor')
|
362
|
+
# User.upsert(user.id, { age: 18 }, { unless_exists: [:age] })
|
363
|
+
#
|
331
364
|
# If conditions were specified and failed the method call returns +nil+.
|
332
365
|
#
|
333
366
|
# +upsert+ uses the +UpdateItem+ operation so it saves changes and loads
|
334
367
|
# an updated document back with one HTTP request.
|
335
368
|
#
|
336
369
|
# Raises a +Dynamoid::Errors::UnknownAttribute+ exception if any of the
|
337
|
-
# attributes is not
|
370
|
+
# attributes is not declared in the model class.
|
338
371
|
#
|
339
372
|
# @param hash_key_value [Scalar value] hash key
|
340
373
|
# @param range_key_value [Scalar value] range key (optional)
|
@@ -390,7 +423,7 @@ module Dynamoid
|
|
390
423
|
# @param hash_key_value [Scalar value] hash key
|
391
424
|
# @param range_key_value [Scalar value] range key (optional)
|
392
425
|
# @param counters [Hash] value to increase by
|
393
|
-
# @option counters [true | Symbol | Array
|
426
|
+
# @option counters [true | Symbol | Array<Symbol>] :touch to update update_at attribute and optionally the specified ones
|
394
427
|
# @return [Model class] self
|
395
428
|
def inc(hash_key_value, range_key_value = nil, counters)
|
396
429
|
Inc.call(self, hash_key_value, range_key_value, counters)
|
@@ -476,7 +509,7 @@ module Dynamoid
|
|
476
509
|
#
|
477
510
|
# +save+ by default sets timestamps attributes - +created_at+ and
|
478
511
|
# +updated_at+ when creates new model and updates +updated_at+ attribute
|
479
|
-
# when
|
512
|
+
# when updates already existing one.
|
480
513
|
#
|
481
514
|
# Changing +updated_at+ attribute at updating a model can be skipped with
|
482
515
|
# +touch: false+ option:
|
@@ -507,7 +540,10 @@ module Dynamoid
|
|
507
540
|
# @return [true|false] Whether saving successful or not
|
508
541
|
# @since 0.2.0
|
509
542
|
def save(options = {})
|
510
|
-
|
543
|
+
if Dynamoid.config.create_table_on_save
|
544
|
+
self.class.create_table(sync: true)
|
545
|
+
end
|
546
|
+
|
511
547
|
create_or_update = new_record? ? :create : :update
|
512
548
|
|
513
549
|
run_callbacks(:save) do
|
@@ -518,7 +554,9 @@ module Dynamoid
|
|
518
554
|
end
|
519
555
|
|
520
556
|
# Update multiple attributes at once, saving the object once the updates
|
521
|
-
# are complete.
|
557
|
+
# are complete.
|
558
|
+
#
|
559
|
+
# Returns +true+ if saving is successful and +false+
|
522
560
|
# otherwise.
|
523
561
|
#
|
524
562
|
# user.update_attributes(age: 27, last_name: 'Tylor')
|
@@ -618,6 +656,15 @@ module Dynamoid
|
|
618
656
|
# t.add(age: 1)
|
619
657
|
# end
|
620
658
|
#
|
659
|
+
# To check if some attribute (or attributes) isn't stored in a DynamoDB
|
660
|
+
# item (e.g. it wasn't set explicitly) there is another condition -
|
661
|
+
# +unless_exists+:
|
662
|
+
#
|
663
|
+
# user = User.create(name: 'Tylor')
|
664
|
+
# user.update!(unless_exists: [:age]) do |t|
|
665
|
+
# t.set(age: 18)
|
666
|
+
# end
|
667
|
+
#
|
621
668
|
# If a document doesn't meet conditions it raises
|
622
669
|
# +Dynamoid::Errors::StaleObjectError+ exception.
|
623
670
|
#
|
@@ -642,12 +689,12 @@ module Dynamoid
|
|
642
689
|
update_item_options = options.merge(conditions: conditions)
|
643
690
|
|
644
691
|
new_attrs = Dynamoid.adapter.update_item(table_name, hash_key, update_item_options) do |t|
|
645
|
-
|
692
|
+
item_updater = ItemUpdaterWithDumping.new(self.class, t)
|
693
|
+
|
694
|
+
item_updater.add(lock_version: 1) if self.class.attributes[:lock_version]
|
646
695
|
|
647
696
|
if self.class.timestamps_enabled?
|
648
|
-
|
649
|
-
time_now_dumped = Dumping.dump_field(time_now, self.class.attributes[:updated_at])
|
650
|
-
t.set(updated_at: time_now_dumped)
|
697
|
+
item_updater.set(updated_at: DateTime.now.in_time_zone(Time.zone))
|
651
698
|
end
|
652
699
|
|
653
700
|
yield t
|
@@ -714,6 +761,15 @@ module Dynamoid
|
|
714
761
|
# t.add(age: 1)
|
715
762
|
# end
|
716
763
|
#
|
764
|
+
# To check if some attribute (or attributes) isn't stored in a DynamoDB
|
765
|
+
# item (e.g. it wasn't set explicitly) there is another condition -
|
766
|
+
# +unless_exists+:
|
767
|
+
#
|
768
|
+
# user = User.create(name: 'Tylor')
|
769
|
+
# user.update(unless_exists: [:age]) do |t|
|
770
|
+
# t.set(age: 18)
|
771
|
+
# end
|
772
|
+
#
|
717
773
|
# If a document doesn't meet conditions it just returns +false+. Otherwise it returns +true+.
|
718
774
|
#
|
719
775
|
# It will increment the +lock_version+ attribute if a table has the column,
|
@@ -769,7 +825,7 @@ module Dynamoid
|
|
769
825
|
#
|
770
826
|
# @param attribute [Symbol] attribute name
|
771
827
|
# @param by [Numeric] value to add (optional)
|
772
|
-
# @param touch [true | Symbol | Array
|
828
|
+
# @param touch [true | Symbol | Array<Symbol>] to update update_at attribute and optionally the specified ones
|
773
829
|
# @return [Dynamoid::Document] self
|
774
830
|
def increment!(attribute, by = 1, touch: nil)
|
775
831
|
increment(attribute, by)
|
@@ -820,7 +876,7 @@ module Dynamoid
|
|
820
876
|
#
|
821
877
|
# @param attribute [Symbol] attribute name
|
822
878
|
# @param by [Numeric] value to subtract (optional)
|
823
|
-
# @param touch [true | Symbol | Array
|
879
|
+
# @param touch [true | Symbol | Array<Symbol>] to update update_at attribute and optionally the specified ones
|
824
880
|
# @return [Dynamoid::Document] self
|
825
881
|
def decrement!(attribute, by = 1, touch: nil)
|
826
882
|
increment!(attribute, -by, touch: touch)
|
@@ -889,7 +945,7 @@ module Dynamoid
|
|
889
945
|
|
890
946
|
Dynamoid.adapter.delete(self.class.table_name, hash_key, options)
|
891
947
|
|
892
|
-
self.class.associations.
|
948
|
+
self.class.associations.each_key do |name|
|
893
949
|
send(name).disassociate_source
|
894
950
|
end
|
895
951
|
|
@@ -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
|