aws-record 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +335 -0
  3. data/LICENSE +202 -0
  4. data/VERSION +1 -0
  5. data/lib/aws-record/record/attribute.rb +9 -21
  6. data/lib/aws-record/record/attributes.rb +68 -78
  7. data/lib/aws-record/record/batch.rb +13 -12
  8. data/lib/aws-record/record/batch_read.rb +5 -2
  9. data/lib/aws-record/record/batch_write.rb +1 -12
  10. data/lib/aws-record/record/buildable_search.rb +33 -28
  11. data/lib/aws-record/record/client_configuration.rb +10 -21
  12. data/lib/aws-record/record/dirty_tracking.rb +30 -44
  13. data/lib/aws-record/record/errors.rb +1 -13
  14. data/lib/aws-record/record/item_collection.rb +5 -16
  15. data/lib/aws-record/record/item_data.rb +4 -18
  16. data/lib/aws-record/record/item_operations.rb +86 -93
  17. data/lib/aws-record/record/key_attributes.rb +1 -14
  18. data/lib/aws-record/record/marshalers/boolean_marshaler.rb +2 -16
  19. data/lib/aws-record/record/marshalers/date_marshaler.rb +1 -15
  20. data/lib/aws-record/record/marshalers/date_time_marshaler.rb +2 -14
  21. data/lib/aws-record/record/marshalers/epoch_time_marshaler.rb +1 -14
  22. data/lib/aws-record/record/marshalers/float_marshaler.rb +3 -19
  23. data/lib/aws-record/record/marshalers/integer_marshaler.rb +3 -19
  24. data/lib/aws-record/record/marshalers/list_marshaler.rb +2 -16
  25. data/lib/aws-record/record/marshalers/map_marshaler.rb +2 -16
  26. data/lib/aws-record/record/marshalers/numeric_set_marshaler.rb +3 -16
  27. data/lib/aws-record/record/marshalers/string_marshaler.rb +2 -16
  28. data/lib/aws-record/record/marshalers/string_set_marshaler.rb +3 -16
  29. data/lib/aws-record/record/marshalers/time_marshaler.rb +1 -14
  30. data/lib/aws-record/record/model_attributes.rb +14 -35
  31. data/lib/aws-record/record/query.rb +7 -21
  32. data/lib/aws-record/record/secondary_indexes.rb +23 -42
  33. data/lib/aws-record/record/table_config.rb +52 -74
  34. data/lib/aws-record/record/table_migration.rb +43 -66
  35. data/lib/aws-record/record/transactions.rb +67 -38
  36. data/lib/aws-record/record/version.rb +2 -13
  37. data/lib/aws-record/record.rb +30 -49
  38. metadata +14 -5
@@ -1,10 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Aws
2
4
  module Record
3
5
  module Transactions
4
6
  extend ClientConfiguration
5
7
 
6
8
  class << self
7
-
8
9
  # @example Usage Example
9
10
  # class TableOne
10
11
  # include Aws::Record
@@ -26,15 +27,26 @@ module Aws
26
27
  # ) # => results.responses contains nil or marshalled items
27
28
  # results.responses.map { |r| r.class } # [TableOne, TableTwo, TableTwo]
28
29
  #
29
- # Provides a way to run a transactional find across multiple DynamoDB
30
+ # Provides support for the
31
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#transact_get_items-instance_method
32
+ # Aws::DynamoDB::Client#transact_get_item} for aws-record models.
33
+ #
34
+ # This method runs a transactional find across multiple DynamoDB
30
35
  # items, including transactions which get items across multiple actual
31
- # or virtual tables.
36
+ # or virtual tables. This call can contain up to 100 item keys.
37
+ #
38
+ # DynamoDB will reject the request if any of the following is true:
39
+ # * A conflicting operation is in the process of updating an item to be read.
40
+ # * There is insufficient provisioned capacity for the transaction to be completed.
41
+ # * There is a user error, such as an invalid data format.
42
+ # * The aggregate size of the items in the transaction cannot exceed 4 MB.
32
43
  #
33
44
  # @param [Hash] opts Options to pass through to
34
- # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#transact_get_items-instance_method Aws::DynamoDB::Client#transact_get_items},
35
- # with the exception of the :transact_items array, which uses the
36
- # +#tfind_opts+ operation on your model class to provide extra
37
- # metadata used to marshal your items after retrieval.
45
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#transact_get_items-instance_method
46
+ # Aws::DynamoDB::Client#transact_get_items}, with the exception of the
47
+ # +:transact_items+ array, which uses the {ItemOperations.ItemOperationsClassMethods.tfind_opts #tfind_opts}
48
+ # operation on your model class to provide extra metadata
49
+ # used to marshal your items after retrieval.
38
50
  # @option opts [Array] :transact_items A set of +#tfind_opts+ results,
39
51
  # such as those created by the usage example.
40
52
  # @option opts [Aws::DynamoDB::Client] :client Optionally, you can pass
@@ -58,7 +70,6 @@ module Aws
58
70
  client_resp = client.transact_get_items(
59
71
  request_opts
60
72
  )
61
- responses = client_resp.responses
62
73
  index = -1
63
74
  ret = OpenStruct.new
64
75
  ret.consumed_capacity = client_resp.consumed_capacity
@@ -137,7 +148,11 @@ module Aws
137
148
  # ]
138
149
  # )
139
150
  #
140
- # Provides a way to pass in aws-record items into transactional writes,
151
+ # Provides support for the
152
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#transact_write_items-instance_method
153
+ # Aws::DynamoDB::Client#transact_write_items} for aws-record models.
154
+ #
155
+ # This method passes in aws-record items into transactional writes,
141
156
  # as well as adding the ability to run 'save' commands in a transaction
142
157
  # while allowing aws-record to determine if a :put or :update operation
143
158
  # is most appropriate. +#transact_write+ supports 5 different transact
@@ -145,7 +160,7 @@ module Aws
145
160
  # - save: Behaves much like the +#save+ operation on the item itself.
146
161
  # If the keys are dirty, and thus it appears to be a new item, will
147
162
  # create a :put operation with a conditional check on the item's
148
- # existance. Note that you cannot bring your own conditional
163
+ # existence. Note that you cannot bring your own conditional
149
164
  # expression in this case. If you wish to force put or add your
150
165
  # own conditional checks, use the :put operation.
151
166
  # - put: Does a force put for the given item key and model.
@@ -153,13 +168,28 @@ module Aws
153
168
  # - delete: Deletes the given item.
154
169
  # - check: Takes the result of +#transact_check_expression+,
155
170
  # performing the specified check as a part of the transaction.
171
+ # See {ItemOperations.ItemOperationsClassMethods.transact_check_expression #transact_check_expression}
172
+ # for more information.
173
+ #
174
+ # This call contain up to 100 action requests.
175
+ #
176
+ # DynamoDB will reject the request if any of the following is true:
177
+ # * A condition in one of the condition expressions is not met.
178
+ # * An ongoing operation is in the process of updating the same item.
179
+ # * There is insufficient provisioned capacity for the transaction to
180
+ # be completed.
181
+ # * An item size becomes too large (bigger than 400 KB), a local secondary
182
+ # index (LSI) becomes too large, or a similar validation error occurs
183
+ # because of changes made by the transaction.
184
+ # * The aggregate size of the items in the transaction exceeds 4 MB.
185
+ # * There is a user error, such as an invalid data format.
156
186
  #
157
187
  # @param [Hash] opts Options to pass through to
158
- # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#transact_write_items-instance_method Aws::DynamoDB::Client#transact_write_items}
159
- # with the exception of :transact_items array, which is transformed
160
- # to use your item to populate the :key, :table_name, :item, and/or
161
- # :update_expression parameters as appropriate. See the usage example
162
- # for a comprehensive set of combinations.
188
+ # {https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#transact_write_items-instance_method
189
+ # Aws::DynamoDB::Client#transact_write_items} with the exception of
190
+ # :transact_items array, which is transformed to use your item to populate
191
+ # the :key, :table_name, :item, and/or :update_expression parameters
192
+ # as appropriate. See the usage example for a comprehensive set of combinations.
163
193
  # @option opts [Array] :transact_items An array of hashes, accepting
164
194
  # +:save+, +:put+, +:delete+, +:update+, and +:check+ as specified.
165
195
  # @option opts [Aws::DynamoDB::Client] :client Optionally, you can
@@ -180,35 +210,35 @@ module Aws
180
210
  opts[:transact_items] = transact_items
181
211
  resp = client.transact_write_items(opts)
182
212
  # mark all items clean/destroyed as needed if we didn't raise an exception
183
- dirty_items.each { |i| i.clean! }
184
- delete_items.each { |i| i.instance_variable_get("@data").destroyed = true }
213
+ dirty_items.each(&:clean!)
214
+ delete_items.each { |i| i.instance_variable_get('@data').destroyed = true }
185
215
  resp
186
216
  end
187
217
 
188
218
  private
219
+
189
220
  def _transform_transact_write_items(transact_items, dirty_items, delete_items)
190
221
  transact_items.map do |item|
191
222
  # this code will assume users only provided one operation, and
192
223
  # will fail down the line if that assumption is wrong
193
- if save_record = item.delete(:save)
224
+ if (save_record = item.delete(:save))
194
225
  dirty_items << save_record
195
226
  _transform_save_record(save_record, item)
196
- elsif put_record = item.delete(:put)
227
+ elsif (put_record = item.delete(:put))
197
228
  dirty_items << put_record
198
229
  _transform_put_record(put_record, item)
199
- elsif delete_record = item.delete(:delete)
230
+ elsif (delete_record = item.delete(:delete))
200
231
  delete_items << delete_record
201
232
  _transform_delete_record(delete_record, item)
202
- elsif update_record = item.delete(:update)
233
+ elsif (update_record = item.delete(:update))
203
234
  dirty_items << update_record
204
235
  _transform_update_record(update_record, item)
205
- elsif check_record = item.delete(:check)
236
+ elsif (check_record = item.delete(:check))
206
237
  _transform_check_record(check_record, item)
207
238
  else
208
- raise ArgumentError.new(
209
- "Invalid transact write item, must include an operation of "\
210
- "type :save, :update, :delete, :update, or :check - #{item}"
211
- )
239
+ raise ArgumentError, 'Invalid transact write item, must include an operation of '\
240
+ "type :save, :update, :delete, :update, or :check - #{item}"
241
+
212
242
  end
213
243
  end
214
244
  end
@@ -219,16 +249,15 @@ module Aws
219
249
  if save_record.send(:expect_new_item?)
220
250
  safety_expression = save_record.send(:prevent_overwrite_expression)
221
251
  if opts.include?(:condition_expression)
222
- raise Errors::TransactionalSaveConditionCollision.new(
223
- "Transactional write includes a :save operation that would "\
224
- "result in a 'safe put' for the given item, yet a "\
225
- "condition expression was also provided. This is not "\
226
- "currently supported. You should rewrite this case to use "\
227
- "a :put transaction, adding the existence check to your "\
228
- "own condition expression if desired.\n"\
229
- "\tItem: #{JSON.pretty_unparse(save_record.to_h)}\n"\
230
- "\tExtra Options: #{JSON.pretty_unparse(opts)}"
231
- )
252
+ raise Errors::TransactionalSaveConditionCollision,
253
+ 'Transactional write includes a :save operation that would '\
254
+ "result in a 'safe put' for the given item, yet a "\
255
+ 'condition expression was also provided. This is not '\
256
+ 'currently supported. You should rewrite this case to use '\
257
+ 'a :put transaction, adding the existence check to your '\
258
+ "own condition expression if desired.\n"\
259
+ "\tItem: #{JSON.pretty_unparse(save_record.to_h)}\n"\
260
+ "\tExtra Options: #{JSON.pretty_unparse(opts)}"
232
261
  else
233
262
  opts = opts.merge(safety_expression)
234
263
  _transform_put_record(save_record, opts)
@@ -264,12 +293,12 @@ module Aws
264
293
  opts[:key] = update_record.send(:key_values)
265
294
  opts[:update_expression] = uex
266
295
  # need to combine expression attribute names and values
267
- if names = opts[:expression_attribute_names]
296
+ if (names = opts[:expression_attribute_names])
268
297
  opts[:expression_attribute_names] = exp_attr_names.merge(names)
269
298
  else
270
299
  opts[:expression_attribute_names] = exp_attr_names
271
300
  end
272
- if values = opts[:expression_attribute_values]
301
+ if (values = opts[:expression_attribute_values])
273
302
  opts[:expression_attribute_values] = exp_attr_values.merge(values)
274
303
  else
275
304
  opts[:expression_attribute_values] = exp_attr_values
@@ -1,18 +1,7 @@
1
- # Copyright 2015-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License"). You may not
4
- # use this file except in compliance with the License. A copy of the License is
5
- # located at
6
- #
7
- # http://aws.amazon.com/apache2.0/
8
- #
9
- # or in the "license" file accompanying this file. This file is distributed on
10
- # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
- # or implied. See the License for the specific language governing permissions
12
- # and limitations under the License.
1
+ # frozen_string_literal: true
13
2
 
14
3
  module Aws
15
4
  module Record
16
- VERSION = '2.7.0'
5
+ VERSION = File.read(File.expand_path('../../../../VERSION', __FILE__)).strip
17
6
  end
18
7
  end
@@ -1,18 +1,6 @@
1
- # Copyright 2015-2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License"). You may not
4
- # use this file except in compliance with the License. A copy of the License is
5
- # located at
6
- #
7
- # http://aws.amazon.com/apache2.0/
8
- #
9
- # or in the "license" file accompanying this file. This file is distributed on
10
- # an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11
- # or implied. See the License for the specific language governing permissions
12
- # and limitations under the License.
1
+ # frozen_string_literal: true
13
2
 
14
3
  module Aws
15
-
16
4
  # +Aws::Record+ is the module you include in your model classes in order to
17
5
  # decorate them with the Amazon DynamoDB integration methods provided by this
18
6
  # library. Methods you can use are shown below, in sub-modules organized by
@@ -84,9 +72,7 @@ module Aws
84
72
  sub_class.send(:include, DirtyTracking)
85
73
  sub_class.send(:include, Query)
86
74
  sub_class.send(:include, SecondaryIndexes)
87
- if Aws::Record.extends_record?(sub_class)
88
- inherit_track_mutations(sub_class)
89
- end
75
+ inherit_track_mutations(sub_class) if Aws::Record.extends_record?(sub_class)
90
76
  end
91
77
 
92
78
  # @api private
@@ -94,18 +80,21 @@ module Aws
94
80
  klass.superclass.include?(Aws::Record)
95
81
  end
96
82
 
83
+ # @api private
84
+ def self.inherit_track_mutations(klass)
85
+ superclass_track_mutations = klass.superclass.instance_variable_get('@track_mutations')
86
+ klass.instance_variable_set('@track_mutations', superclass_track_mutations)
87
+ end
88
+
89
+ private_class_method :inherit_track_mutations
90
+
97
91
  private
92
+
98
93
  def dynamodb_client
99
94
  self.class.dynamodb_client
100
95
  end
101
96
 
102
- def self.inherit_track_mutations(klass)
103
- superclass_track_mutations = klass.superclass.instance_variable_get("@track_mutations")
104
- klass.instance_variable_set("@track_mutations", superclass_track_mutations)
105
- end
106
-
107
97
  module RecordClassMethods
108
-
109
98
  # Returns the Amazon DynamoDB table name for this model class.
110
99
  #
111
100
  # By default, this will simply be the name of the class. However, you can
@@ -127,14 +116,16 @@ module Aws
127
116
  # MyTable.table_name # => "MyTable"
128
117
  # MyOtherTable.table_name # => "test_MyTable"
129
118
  def table_name
119
+ # rubocop:disable Style/RedundantSelf
130
120
  @table_name ||= begin
131
121
  if Aws::Record.extends_record?(self) &&
132
- default_table_name(self.superclass) != self.superclass.table_name
122
+ default_table_name(self.superclass) != self.superclass.table_name
133
123
  self.superclass.instance_variable_get('@table_name')
134
124
  else
135
125
  default_table_name(self)
136
126
  end
137
127
  end
128
+ # rubocop:enable Style/RedundantSelf
138
129
  end
139
130
 
140
131
  # Allows you to set a custom Amazon DynamoDB table name for this model
@@ -186,7 +177,7 @@ module Aws
186
177
  # end
187
178
  #
188
179
  # Dog.table_name # => "DogTable"
189
- def set_table_name(name)
180
+ def set_table_name(name) # rubocop:disable Naming/AccessorMethodName
190
181
  @table_name = name
191
182
  end
192
183
 
@@ -198,32 +189,24 @@ module Aws
198
189
  # @raise [Aws::Record::Errors::TableDoesNotExist] if the table name does
199
190
  # not exist in DynamoDB.
200
191
  def provisioned_throughput
201
- begin
202
- resp = dynamodb_client.describe_table(table_name: table_name)
203
- throughput = resp.table.provisioned_throughput
204
- return {
205
- read_capacity_units: throughput.read_capacity_units,
206
- write_capacity_units: throughput.write_capacity_units
207
- }
208
- rescue DynamoDB::Errors::ResourceNotFoundException
209
- raise Record::Errors::TableDoesNotExist
210
- end
192
+ resp = dynamodb_client.describe_table(table_name: table_name)
193
+ throughput = resp.table.provisioned_throughput
194
+ {
195
+ read_capacity_units: throughput.read_capacity_units,
196
+ write_capacity_units: throughput.write_capacity_units
197
+ }
198
+ rescue DynamoDB::Errors::ResourceNotFoundException
199
+ raise Record::Errors::TableDoesNotExist
211
200
  end
212
201
 
213
202
  # Checks if the model's table name exists in Amazon DynamoDB.
214
203
  #
215
204
  # @return [Boolean] true if the table does exist, false if it does not.
216
205
  def table_exists?
217
- begin
218
- resp = dynamodb_client.describe_table(table_name: table_name)
219
- if resp.table.table_status == "ACTIVE"
220
- true
221
- else
222
- false
223
- end
224
- rescue DynamoDB::Errors::ResourceNotFoundException
225
- false
226
- end
206
+ resp = dynamodb_client.describe_table(table_name: table_name)
207
+ resp.table.table_status == 'ACTIVE'
208
+ rescue DynamoDB::Errors::ResourceNotFoundException
209
+ false
227
210
  end
228
211
 
229
212
  # Turns off mutation tracking for all attributes in the model.
@@ -257,17 +240,15 @@ module Aws
257
240
  end
258
241
 
259
242
  def model_valid?
260
- if @keys.hash_key.nil?
261
- raise Errors::InvalidModel.new("Table models must include a hash key")
262
- end
243
+ raise Errors::InvalidModel, 'Table models must include a hash key' if @keys.hash_key.nil?
263
244
  end
264
245
 
265
246
  private
247
+
266
248
  def default_table_name(klass)
267
249
  return unless klass.name
268
- klass.name.split("::").join("_")
250
+ klass.name.split('::').join('_')
269
251
  end
270
-
271
252
  end
272
253
  end
273
254
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-record
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.10.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-13 00:00:00.000000000 Z
11
+ date: 2023-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-dynamodb
@@ -16,14 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.18'
19
+ version: '1'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 1.85.0
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
27
  - - "~>"
25
28
  - !ruby/object:Gem::Version
26
- version: '1.18'
29
+ version: '1'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 1.85.0
27
33
  description: Provides an object mapping abstraction for Amazon DynamoDB.
28
34
  email:
29
35
  - mamuller@amazon.com
@@ -32,6 +38,9 @@ executables: []
32
38
  extensions: []
33
39
  extra_rdoc_files: []
34
40
  files:
41
+ - CHANGELOG.md
42
+ - LICENSE
43
+ - VERSION
35
44
  - lib/aws-record.rb
36
45
  - lib/aws-record/record.rb
37
46
  - lib/aws-record/record/attribute.rb
@@ -85,7 +94,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
85
94
  - !ruby/object:Gem::Version
86
95
  version: '0'
87
96
  requirements: []
88
- rubygems_version: 3.3.3
97
+ rubygems_version: 3.4.10
89
98
  signing_key:
90
99
  specification_version: 4
91
100
  summary: AWS Record library for Amazon DynamoDB