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.
- 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
|