dynamoid 3.13.0 → 3.14.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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -4
  3. data/README.md +60 -1584
  4. data/lib/dynamoid/associations/association.rb +10 -2
  5. data/lib/dynamoid/associations/belongs_to.rb +3 -1
  6. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +0 -1
  7. data/lib/dynamoid/associations/has_many.rb +0 -1
  8. data/lib/dynamoid/associations/has_one.rb +1 -2
  9. data/lib/dynamoid/associations/many_association.rb +1 -0
  10. data/lib/dynamoid/associations.rb +64 -48
  11. data/lib/dynamoid/components.rb +1 -0
  12. data/lib/dynamoid/criteria/chain.rb +43 -30
  13. data/lib/dynamoid/dirty.rb +13 -3
  14. data/lib/dynamoid/document.rb +29 -21
  15. data/lib/dynamoid/fields.rb +55 -41
  16. data/lib/dynamoid/finders.rb +1 -1
  17. data/lib/dynamoid/indexes.rb +29 -21
  18. data/lib/dynamoid/persistence/inc.rb +15 -7
  19. data/lib/dynamoid/persistence/save.rb +21 -14
  20. data/lib/dynamoid/persistence.rb +88 -54
  21. data/lib/dynamoid/transactions/mutation/base.rb +76 -0
  22. data/lib/dynamoid/transactions/mutation/builders/delete_request_builder.rb +44 -0
  23. data/lib/dynamoid/transactions/mutation/builders/update_request_builder.rb +139 -0
  24. data/lib/dynamoid/transactions/mutation/create.rb +52 -0
  25. data/lib/dynamoid/transactions/mutation/delete_with_instance.rb +80 -0
  26. data/lib/dynamoid/transactions/mutation/delete_with_primary_key.rb +62 -0
  27. data/lib/dynamoid/transactions/mutation/destroy.rb +96 -0
  28. data/lib/dynamoid/transactions/mutation/import.rb +84 -0
  29. data/lib/dynamoid/transactions/mutation/inc.rb +101 -0
  30. data/lib/dynamoid/transactions/mutation/increment.rb +63 -0
  31. data/lib/dynamoid/transactions/mutation/save.rb +194 -0
  32. data/lib/dynamoid/transactions/mutation/touch.rb +99 -0
  33. data/lib/dynamoid/transactions/mutation/update_attributes.rb +49 -0
  34. data/lib/dynamoid/transactions/mutation/update_fields.rb +185 -0
  35. data/lib/dynamoid/transactions/mutation/upsert.rb +94 -0
  36. data/lib/dynamoid/transactions/mutation.rb +935 -0
  37. data/lib/dynamoid/transactions/retrieval/find.rb +140 -0
  38. data/lib/dynamoid/transactions/retrieval.rb +150 -0
  39. data/lib/dynamoid/transactions.rb +63 -0
  40. data/lib/dynamoid/version.rb +1 -1
  41. data/lib/dynamoid.rb +1 -2
  42. metadata +23 -17
  43. data/lib/dynamoid/transaction_read/find.rb +0 -137
  44. data/lib/dynamoid/transaction_read.rb +0 -146
  45. data/lib/dynamoid/transaction_write/base.rb +0 -59
  46. data/lib/dynamoid/transaction_write/create.rb +0 -49
  47. data/lib/dynamoid/transaction_write/delete_with_instance.rb +0 -65
  48. data/lib/dynamoid/transaction_write/delete_with_primary_key.rb +0 -64
  49. data/lib/dynamoid/transaction_write/destroy.rb +0 -84
  50. data/lib/dynamoid/transaction_write/item_updater.rb +0 -60
  51. data/lib/dynamoid/transaction_write/save.rb +0 -177
  52. data/lib/dynamoid/transaction_write/update_attributes.rb +0 -46
  53. data/lib/dynamoid/transaction_write/update_fields.rb +0 -247
  54. data/lib/dynamoid/transaction_write/upsert.rb +0 -113
  55. data/lib/dynamoid/transaction_write.rb +0 -673
@@ -26,13 +26,15 @@ module Dynamoid
26
26
  module ClassMethods
27
27
  # Specify a field for a document.
28
28
  #
29
- # class User
30
- # include Dynamoid::Document
29
+ # ```
30
+ # class User
31
+ # include Dynamoid::Document
31
32
  #
32
- # field :last_name
33
- # field :age, :integer
34
- # field :last_sign_in, :datetime
35
- # end
33
+ # field :last_name
34
+ # field :age, :integer
35
+ # field :last_sign_in, :datetime
36
+ # end
37
+ # ```
36
38
  #
37
39
  # Its type determines how it is coerced when read in and out of the
38
40
  # data store. You can specify +string+, +integer+, +number+, +set+, +array+,
@@ -101,35 +103,39 @@ module Dynamoid
101
103
  #
102
104
  # It works in the following way:
103
105
  #
104
- # class User
105
- # include Dynamoid::Document
106
+ # ```
107
+ # class User
108
+ # include Dynamoid::Document
106
109
  #
107
- # field :age, :integer
108
- # end
110
+ # field :age, :integer
111
+ # end
109
112
  #
110
- # user = User.new
111
- # user.age # => nil
112
- # user.age? # => false
113
+ # user = User.new
114
+ # user.age # => nil
115
+ # user.age? # => false
113
116
  #
114
- # user.age = 20
115
- # user.age? # => true
117
+ # user.age = 20
118
+ # user.age? # => true
116
119
  #
117
- # user.age = '21'
118
- # user.age # => 21 - integer
119
- # user.age_before_type_cast # => '21' - string
120
+ # user.age = '21'
121
+ # user.age # => 21 - integer
122
+ # user.age_before_type_cast # => '21' - string
123
+ # ```
120
124
  #
121
125
  # There is also an option +alias+ which allows to use another name for a
122
126
  # field:
123
127
  #
124
- # class User
125
- # include Dynamoid::Document
128
+ # ```
129
+ # class User
130
+ # include Dynamoid::Document
126
131
  #
127
- # field :firstName, :string, alias: :first_name
128
- # end
132
+ # field :firstName, :string, alias: :first_name
133
+ # end
129
134
  #
130
- # user = User.new(firstName: 'Michael')
131
- # user.firstName # Michael
132
- # user.first_name # Michael
135
+ # user = User.new(firstName: 'Michael')
136
+ # user.firstName # Michael
137
+ # user.first_name # Michael
138
+ # ```
133
139
  #
134
140
  # @param name [Symbol] name of the field
135
141
  # @param type [Symbol] type of the field (optional)
@@ -152,11 +158,13 @@ module Dynamoid
152
158
 
153
159
  # Declare a table range key.
154
160
  #
155
- # class User
156
- # include Dynamoid::Document
161
+ # ```
162
+ # class User
163
+ # include Dynamoid::Document
157
164
  #
158
- # range :last_name
159
- # end
165
+ # range :last_name
166
+ # end
167
+ # ```
160
168
  #
161
169
  # By default a range key is a string. In order to use any other type it
162
170
  # should be specified as a second argument:
@@ -187,29 +195,35 @@ module Dynamoid
187
195
  #
188
196
  # The +table+ method can be used to override the defaults:
189
197
  #
190
- # class User
191
- # include Dynamoid::Document
198
+ # ```
199
+ # class User
200
+ # include Dynamoid::Document
192
201
  #
193
- # table name: :customers, key: :uuid
194
- # end
202
+ # table name: :customers, key: :uuid
203
+ # end
204
+ # ```
195
205
  #
196
206
  # The hash key field is declared by default and a type is a string. If
197
207
  # another type is needed the field should be declared explicitly:
198
208
  #
199
- # class User
200
- # include Dynamoid::Document
209
+ # ```
210
+ # class User
211
+ # include Dynamoid::Document
201
212
  #
202
- # field :id, :integer
203
- # end
213
+ # field :id, :integer
214
+ # end
215
+ # ```
204
216
  #
205
217
  # To declare a new attribute with not-default type as a table hash key a
206
218
  # :key_type option can be used:
207
219
  #
208
- # class User
209
- # include Dynamoid::Document
220
+ # ```
221
+ # class User
222
+ # include Dynamoid::Document
210
223
  #
211
- # table key: :user_id, key_type: :integer
212
- # end
224
+ # table key: :user_id, key_type: :integer
225
+ # end
226
+ # ```
213
227
  #
214
228
  # @param options [Hash] options to override default table settings
215
229
  # @option options [Symbol] :name name of a table
@@ -243,7 +243,7 @@ module Dynamoid
243
243
  # field :email, :string
244
244
  # field :age, :integer
245
245
  # field :gender, :string
246
- # field :rank :number
246
+ # field :rank, :number
247
247
  # end
248
248
  #
249
249
  # # NOTE: the first param and the second param are both hashes,
@@ -24,22 +24,26 @@ module Dynamoid
24
24
  # Defines a Global Secondary index on a table. Keys can be specified as
25
25
  # hash-only, or hash & range.
26
26
  #
27
- # class Post
28
- # include Dynamoid::Document
27
+ # ```
28
+ # class Post
29
+ # include Dynamoid::Document
29
30
  #
30
- # field :category
31
+ # field :category
31
32
  #
32
- # global_secondary_index hash_key: :category
33
- # end
33
+ # global_secondary_index hash_key: :category
34
+ # end
35
+ # ```
34
36
  #
35
37
  # The full example with all the options being specified:
36
38
  #
37
- # global_secondary_index hash_key: :category,
38
- # range_key: :created_at,
39
- # name: 'posts_category_created_at_index',
40
- # projected_attributes: :all,
41
- # read_capacity: 100,
42
- # write_capacity: 20
39
+ # ```
40
+ # global_secondary_index hash_key: :category,
41
+ # range_key: :created_at,
42
+ # name: 'posts_category_created_at_index',
43
+ # projected_attributes: :all,
44
+ # read_capacity: 100,
45
+ # write_capacity: 20
46
+ # ```
43
47
  #
44
48
  # Global secondary index should be declared after fields for mentioned
45
49
  # hash key and optional range key are declared (with method +field+)
@@ -88,21 +92,25 @@ module Dynamoid
88
92
  # Defines a local secondary index on a table. Will use the same primary
89
93
  # hash key as the table.
90
94
  #
91
- # class Comment
92
- # include Dynamoid::Document
95
+ # ```
96
+ # class Comment
97
+ # include Dynamoid::Document
93
98
  #
94
- # table hash_key: :post_id
95
- # range :created_at, :datetime
96
- # field :author_id
99
+ # table hash_key: :post_id
100
+ # range :created_at, :datetime
101
+ # field :author_id
97
102
  #
98
- # local_secondary_index range_key: :author_id
99
- # end
103
+ # local_secondary_index range_key: :author_id
104
+ # end
105
+ # ```
100
106
  #
101
107
  # The full example with all the options being specified:
102
108
  #
103
- # local_secondary_index range_key: :created_at,
104
- # name: 'posts_created_at_index',
105
- # projected_attributes: :all
109
+ # ```
110
+ # local_secondary_index range_key: :created_at,
111
+ # name: 'posts_created_at_index',
112
+ # projected_attributes: :all
113
+ # ```
106
114
  #
107
115
  # Local secondary index should be declared after fields for mentioned
108
116
  # hash key and optional range key are declared (with method +field+) as
@@ -6,7 +6,7 @@ module Dynamoid
6
6
  module Persistence
7
7
  # @private
8
8
  class Inc
9
- def self.call(model_class, partition_key, sort_key = nil, counters)
9
+ def self.call(model_class, partition_key, sort_key = nil, counters) # rubocop:disable Style/OptionalArguments
10
10
  new(model_class, partition_key, sort_key, counters).call
11
11
  end
12
12
 
@@ -16,11 +16,14 @@ module Dynamoid
16
16
  @partition_key = partition_key
17
17
  @sort_key = sort_key
18
18
  @counters = counters
19
+ @touch = @counters.delete(:touch)
19
20
  end
20
21
  # rubocop:enable Style/OptionalArguments
21
22
 
22
23
  def call
23
- touch = @counters.delete(:touch)
24
+ validate_primary_key!
25
+ Dynamoid::Persistence::UpdateValidations.validate_attributes_exist(@model_class, @counters)
26
+
24
27
  partition_key_dumped = cast_and_dump(@model_class.hash_key, @partition_key)
25
28
  options = update_item_options(partition_key_dumped)
26
29
 
@@ -31,10 +34,10 @@ module Dynamoid
31
34
  item_updater.add(name => value)
32
35
  end
33
36
 
34
- if touch
37
+ if @touch
35
38
  value = DateTime.now.in_time_zone(Time.zone)
36
39
 
37
- timestamp_attributes_to_touch(touch).each do |name|
40
+ timestamp_attributes_to_touch.each do |name|
38
41
  item_updater.set(name => value)
39
42
  end
40
43
  end
@@ -44,6 +47,11 @@ module Dynamoid
44
47
 
45
48
  private
46
49
 
50
+ def validate_primary_key!
51
+ raise Dynamoid::Errors::MissingHashKey if @partition_key.nil?
52
+ raise Dynamoid::Errors::MissingRangeKey if @model_class.range_key? && @sort_key.nil?
53
+ end
54
+
47
55
  def update_item_options(partition_key_dumped)
48
56
  options = {}
49
57
 
@@ -63,12 +71,12 @@ module Dynamoid
63
71
  options
64
72
  end
65
73
 
66
- def timestamp_attributes_to_touch(touch)
67
- return [] unless touch
74
+ def timestamp_attributes_to_touch
75
+ return [] unless @touch
68
76
 
69
77
  names = []
70
78
  names << :updated_at if @model_class.timestamps_enabled?
71
- names += Array.wrap(touch) if touch != true
79
+ names += Array.wrap(@touch) if @touch != true
72
80
  names
73
81
  end
74
82
 
@@ -30,12 +30,18 @@ module Dynamoid
30
30
 
31
31
  # Add an optimistic locking check if the lock_version column exists
32
32
  if @model.class.attributes[:lock_version]
33
- @model.lock_version = (@model.lock_version || 0) + 1
33
+ if @model.lock_version.nil? && @model.new_record?
34
+ @model.lock_version = 1
35
+ end
36
+
37
+ if @model.lock_version && !@model.changes[:lock_version]
38
+ @model.lock_version += 1
39
+ end
34
40
  end
35
41
 
36
42
  if @model.new_record?
37
43
  attributes_dumped = Dumping.dump_attributes(@model.attributes, @model.class.attributes)
38
- Dynamoid.adapter.write(@model.class.table_name, attributes_dumped, conditions_for_write)
44
+ Dynamoid.adapter.write(@model.class.table_name, attributes_dumped, conditions_to_create_item)
39
45
  else
40
46
  attributes_to_persist = @model.attributes.slice(*@model.changed.map(&:to_sym))
41
47
  partition_key_dumped = dump(@model.class.hash_key, @model.hash_key)
@@ -68,7 +74,7 @@ module Dynamoid
68
74
  end
69
75
 
70
76
  # Should be called after incrementing `lock_version` attribute
71
- def conditions_for_write
77
+ def conditions_to_create_item
72
78
  conditions = {}
73
79
 
74
80
  # Add an 'exists' check to prevent overwriting existing records with new ones
@@ -77,14 +83,6 @@ module Dynamoid
77
83
  conditions[:unless_exists] << @model.range_key
78
84
  end
79
85
 
80
- # Add an optimistic locking check if the lock_version column exists
81
- # Uses the original lock_version value from Dirty API
82
- # in case user changed 'lock_version' manually
83
- if @model.class.attributes[:lock_version] && @model.changes[:lock_version][0]
84
- conditions[:if] ||= {}
85
- conditions[:if][:lock_version] = @model.changes[:lock_version][0]
86
- end
87
-
88
86
  conditions
89
87
  end
90
88
 
@@ -103,9 +101,18 @@ module Dynamoid
103
101
  # Add an optimistic locking check if the lock_version column exists
104
102
  # Uses the original lock_version value from Dirty API
105
103
  # in case user changed 'lock_version' manually
106
- if @model.class.attributes[:lock_version] && @model.changes[:lock_version][0]
107
- conditions[:if] ||= {}
108
- conditions[:if][:lock_version] = @model.changes[:lock_version][0]
104
+ if @model.class.attributes[:lock_version]
105
+ lock_version = if @model.changes[:lock_version]
106
+ @model.changes[:lock_version][0]
107
+ else
108
+ @model.lock_version
109
+ end
110
+
111
+ # skip concurrency control when lock_version is nil
112
+ if lock_version
113
+ conditions[:if] ||= {}
114
+ conditions[:if][:lock_version] = lock_version
115
+ end
109
116
  end
110
117
 
111
118
  options[:conditions] = conditions
@@ -48,17 +48,19 @@ module Dynamoid
48
48
  #
49
49
  # For instance here
50
50
  #
51
- # class User
52
- # include Dynamoid::Document
51
+ # ```
52
+ # class User
53
+ # include Dynamoid::Document
53
54
  #
54
- # table key: :uuid
55
- # range :last_name
55
+ # table key: :uuid
56
+ # range :last_name
56
57
  #
57
- # field :first_name
58
- # field :last_name
59
- # end
58
+ # field :first_name
59
+ # field :last_name
60
+ # end
60
61
  #
61
- # User.create_table
62
+ # User.create_table
63
+ # ```
62
64
  #
63
65
  # +create_table+ method call will create a table +dynamoid_users+ with
64
66
  # hash key +uuid+ and range key +name+, DynamoDB default billing mode and
@@ -186,9 +188,11 @@ module Dynamoid
186
188
  # Instantiates a model and pass it into an optional block to set other
187
189
  # attributes.
188
190
  #
189
- # User.create(first_name: 'Mark') do |u|
190
- # u.age = 21
191
- # end
191
+ # ```
192
+ # User.create(first_name: 'Mark') do |u|
193
+ # u.age = 21
194
+ # end
195
+ # ```
192
196
  #
193
197
  # Validates model and runs callbacks.
194
198
  #
@@ -227,9 +231,11 @@ module Dynamoid
227
231
  # Instantiates a model and pass it into an optional block to set other
228
232
  # attributes.
229
233
  #
230
- # User.create!(first_name: 'Mark') do |u|
231
- # u.age = 21
232
- # end
234
+ # ```
235
+ # User.create!(first_name: 'Mark') do |u|
236
+ # u.age = 21
237
+ # end
238
+ # ```
233
239
  #
234
240
  # Validates model and runs callbacks.
235
241
  #
@@ -448,6 +454,10 @@ module Dynamoid
448
454
  # User.inc('1', age: 2, touch: :viewed_at)
449
455
  # User.inc('1', age: 2, touch: [:viewed_at, :accessed_at])
450
456
  #
457
+ # Raises +Dynamoid::Errors::MissingHashKey+ if a partition key has value
458
+ # +nil+ and raises +Dynamoid::Errors::MissingRangeKey+ if a sort key is
459
+ # required but has value +nil+ or is missing.
460
+ #
451
461
  # @param hash_key_value [Scalar value] hash key
452
462
  # @param range_key_value [Scalar value] range key (optional)
453
463
  # @param counters [Hash] value to increase by
@@ -850,23 +860,29 @@ module Dynamoid
850
860
  # Operation +add+ just adds a value for numeric attributes and join
851
861
  # collections if attribute is a set.
852
862
  #
853
- # user.update! do |t|
854
- # t.add(age: 1, followers_count: 5)
855
- # t.add(hobbies: ['skying', 'climbing'])
856
- # end
863
+ # ```
864
+ # user.update! do |t|
865
+ # t.add(age: 1, followers_count: 5)
866
+ # t.add(hobbies: ['skying', 'climbing'])
867
+ # end
868
+ # ```
857
869
  #
858
870
  # Operation +delete+ is applied to collection attribute types and
859
871
  # substructs one collection from another.
860
872
  #
861
- # user.update! do |t|
862
- # t.delete(hobbies: ['skying'])
863
- # end
873
+ # ```
874
+ # user.update! do |t|
875
+ # t.delete(hobbies: ['skying'])
876
+ # end
877
+ # ```
864
878
  #
865
879
  # Operation +set+ just changes an attribute value:
866
880
  #
867
- # user.update! do |t|
868
- # t.set(age: 21)
869
- # end
881
+ # ```
882
+ # user.update! do |t|
883
+ # t.set(age: 21)
884
+ # end
885
+ # ```
870
886
  #
871
887
  # All the operations work like +ADD+, +DELETE+ and +PUT+ actions supported
872
888
  # by +AttributeUpdates+
@@ -879,18 +895,22 @@ module Dynamoid
879
895
  #
880
896
  # Can update a model conditionaly:
881
897
  #
882
- # user.update!(if: { age: 20 }) do |t|
883
- # t.add(age: 1)
884
- # end
898
+ # ```
899
+ # user.update!(if: { age: 20 }) do |t|
900
+ # t.add(age: 1)
901
+ # end
902
+ # ```
885
903
  #
886
904
  # To check if some attribute (or attributes) isn't stored in a DynamoDB
887
905
  # item (e.g. it wasn't set explicitly) there is another condition -
888
906
  # +unless_exists+:
889
907
  #
890
- # user = User.create(name: 'Tylor')
891
- # user.update!(unless_exists: [:age]) do |t|
892
- # t.set(age: 18)
893
- # end
908
+ # ```
909
+ # user = User.create(name: 'Tylor')
910
+ # user.update!(unless_exists: [:age]) do |t|
911
+ # t.set(age: 18)
912
+ # end
913
+ # ```
894
914
  #
895
915
  # If a document doesn't meet conditions it raises
896
916
  # +Dynamoid::Errors::StaleObjectError+ exception.
@@ -957,36 +977,46 @@ module Dynamoid
957
977
  # Operation +add+ just adds a value for numeric attributes and join
958
978
  # collections if attribute is a set.
959
979
  #
960
- # user.update do |t|
961
- # t.add(age: 1, followers_count: 5)
962
- # t.add(hobbies: ['skying', 'climbing'])
963
- # end
980
+ # ```
981
+ # user.update do |t|
982
+ # t.add(age: 1, followers_count: 5)
983
+ # t.add(hobbies: ['skying', 'climbing'])
984
+ # end
985
+ # ```
964
986
  #
965
987
  # Operation +delete+ is applied to collection attribute types and
966
988
  # substructs one collection from another.
967
989
  #
968
- # user.update do |t|
969
- # t.delete(hobbies: ['skying'])
970
- # end
990
+ # ```
991
+ # user.update do |t|
992
+ # t.delete(hobbies: ['skying'])
993
+ # end
994
+ # ```
971
995
  #
972
996
  # If it's applied to a scalar attribute then the item's attribute is
973
997
  # removed at all:
974
998
  #
975
- # user.update do |t|
976
- # t.delete(age: nil)
977
- # end
999
+ # ```
1000
+ # user.update do |t|
1001
+ # t.delete(age: nil)
1002
+ # end
1003
+ # ```
978
1004
  #
979
1005
  # or even without useless value at all:
980
1006
  #
981
- # user.update do |t|
982
- # t.delete(:age)
983
- # end
1007
+ # ```
1008
+ # user.update do |t|
1009
+ # t.delete(:age)
1010
+ # end
1011
+ # ```
984
1012
  #
985
1013
  # Operation +set+ just changes an attribute value:
986
1014
  #
987
- # user.update do |t|
988
- # t.set(age: 21)
989
- # end
1015
+ # ```
1016
+ # user.update do |t|
1017
+ # t.set(age: 21)
1018
+ # end
1019
+ # ```
990
1020
  #
991
1021
  # All the operations works like +ADD+, +DELETE+ and +PUT+ actions supported
992
1022
  # by +AttributeUpdates+
@@ -995,18 +1025,22 @@ module Dynamoid
995
1025
  #
996
1026
  # Can update a model conditionaly:
997
1027
  #
998
- # user.update(if: { age: 20 }) do |t|
999
- # t.add(age: 1)
1000
- # end
1028
+ # ```
1029
+ # user.update(if: { age: 20 }) do |t|
1030
+ # t.add(age: 1)
1031
+ # end
1032
+ # ```
1001
1033
  #
1002
1034
  # To check if some attribute (or attributes) isn't stored in a DynamoDB
1003
1035
  # item (e.g. it wasn't set explicitly) there is another condition -
1004
1036
  # +unless_exists+:
1005
1037
  #
1006
- # user = User.create(name: 'Tylor')
1007
- # user.update(unless_exists: [:age]) do |t|
1008
- # t.set(age: 18)
1009
- # end
1038
+ # ```
1039
+ # user = User.create(name: 'Tylor')
1040
+ # user.update(unless_exists: [:age]) do |t|
1041
+ # t.set(age: 18)
1042
+ # end
1043
+ # ```
1010
1044
  #
1011
1045
  # If a document doesn't meet conditions it just returns +false+. Otherwise it returns +true+.
1012
1046
  #
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dynamoid
4
+ module Transactions
5
+ class Mutation
6
+ # @private
7
+ class Base
8
+ # Callback called at "initialization" or "registration" an action
9
+ # before changes are persisted. It's a proper place to validate
10
+ # a model or run callbacks
11
+ def on_registration
12
+ raise 'Not implemented'
13
+ end
14
+
15
+ # Callback called after changes are persisted.
16
+ # It's a proper place to mark changes in a model as applied.
17
+ def on_commit
18
+ raise 'Not implemented'
19
+ end
20
+
21
+ # Callback called when a transaction is rolled back.
22
+ # It's a proper place to undo changes made in after_... callbacks.
23
+ def on_rollback
24
+ raise 'Not implemented'
25
+ end
26
+
27
+ # Whether some callback aborted or canceled an action
28
+ def aborted?
29
+ raise 'Not implemented'
30
+ end
31
+
32
+ # Whether there are changes to persist, e.g. updating a model with no
33
+ # attribute changed is skipped.
34
+ def skipped?
35
+ raise 'Not implemented'
36
+ end
37
+
38
+ # Value returned to a user as an action result
39
+ def observable_by_user_result
40
+ raise 'Not implemented'
41
+ end
42
+
43
+ # Coresponding part of a final request body
44
+ def action_requests
45
+ raise 'Not implemented'
46
+ end
47
+
48
+ def self.validate_attribute_names!(model_class, names)
49
+ names.each do |name|
50
+ unless model_class.attributes[name]
51
+ raise Dynamoid::Errors::UnknownAttribute.new(model_class, name)
52
+ end
53
+ end
54
+ end
55
+
56
+ private
57
+
58
+ def validate_attribute_names!(model_class, names)
59
+ self.class.validate_attribute_names!(model_class, names)
60
+ end
61
+
62
+ # copied from aws_sdk_v3
63
+ def sanitize_item(attributes)
64
+ config_value = Dynamoid.config.store_attribute_with_nil_value
65
+ store_attribute_with_nil_value = config_value.nil? ? false : !!config_value
66
+
67
+ attributes.reject do |_, v|
68
+ !store_attribute_with_nil_value && v.nil?
69
+ end.transform_values do |v|
70
+ v.is_a?(Hash) ? v.stringify_keys : v
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end