aws-record 2.10.0 → 2.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 +335 -0
- data/LICENSE +202 -0
- data/VERSION +1 -0
- data/lib/aws-record/record/attribute.rb +9 -21
- data/lib/aws-record/record/attributes.rb +68 -78
- data/lib/aws-record/record/batch.rb +13 -12
- data/lib/aws-record/record/batch_read.rb +5 -2
- data/lib/aws-record/record/batch_write.rb +1 -12
- data/lib/aws-record/record/buildable_search.rb +33 -28
- data/lib/aws-record/record/client_configuration.rb +10 -21
- data/lib/aws-record/record/dirty_tracking.rb +30 -44
- data/lib/aws-record/record/errors.rb +1 -13
- data/lib/aws-record/record/item_collection.rb +5 -16
- data/lib/aws-record/record/item_data.rb +4 -18
- data/lib/aws-record/record/item_operations.rb +86 -93
- data/lib/aws-record/record/key_attributes.rb +1 -14
- data/lib/aws-record/record/marshalers/boolean_marshaler.rb +2 -16
- data/lib/aws-record/record/marshalers/date_marshaler.rb +1 -15
- data/lib/aws-record/record/marshalers/date_time_marshaler.rb +2 -14
- data/lib/aws-record/record/marshalers/epoch_time_marshaler.rb +1 -14
- data/lib/aws-record/record/marshalers/float_marshaler.rb +3 -19
- data/lib/aws-record/record/marshalers/integer_marshaler.rb +3 -19
- data/lib/aws-record/record/marshalers/list_marshaler.rb +2 -16
- data/lib/aws-record/record/marshalers/map_marshaler.rb +2 -16
- data/lib/aws-record/record/marshalers/numeric_set_marshaler.rb +3 -16
- data/lib/aws-record/record/marshalers/string_marshaler.rb +2 -16
- data/lib/aws-record/record/marshalers/string_set_marshaler.rb +3 -16
- data/lib/aws-record/record/marshalers/time_marshaler.rb +1 -14
- data/lib/aws-record/record/model_attributes.rb +14 -35
- data/lib/aws-record/record/query.rb +7 -21
- data/lib/aws-record/record/secondary_indexes.rb +23 -42
- data/lib/aws-record/record/table_config.rb +52 -74
- data/lib/aws-record/record/table_migration.rb +43 -66
- data/lib/aws-record/record/transactions.rb +67 -38
- data/lib/aws-record/record/version.rb +2 -13
- data/lib/aws-record/record.rb +30 -49
- 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
|
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
|
35
|
-
# with the exception of the
|
36
|
-
#
|
37
|
-
#
|
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
|
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
|
-
#
|
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
|
159
|
-
# with the exception of
|
160
|
-
# to use your item to populate
|
161
|
-
# :
|
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
|
184
|
-
delete_items.each { |i| i.instance_variable_get(
|
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
|
209
|
-
|
210
|
-
|
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
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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
|
-
#
|
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 =
|
5
|
+
VERSION = File.read(File.expand_path('../../../../VERSION', __FILE__)).strip
|
17
6
|
end
|
18
7
|
end
|
data/lib/aws-record/record.rb
CHANGED
@@ -1,18 +1,6 @@
|
|
1
|
-
#
|
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
|
-
|
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
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
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
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
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(
|
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.
|
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-
|
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
|
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
|
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.
|
97
|
+
rubygems_version: 3.4.10
|
89
98
|
signing_key:
|
90
99
|
specification_version: 4
|
91
100
|
summary: AWS Record library for Amazon DynamoDB
|