aws-record 1.0.3 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 707c0dda4d338ec8c39441124f050922181ca6a5
|
4
|
+
data.tar.gz: 945f67f08fa5230b7c3f7dac7d95138a1017ee9c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f58be26c4c9c1215a293fbbcc1484ca4993d305edeac7e16182df127a9fe80620135024039190eb9894d3ed5f58554a02cf93cd091b73c9b133c7c739d4a90ba
|
7
|
+
data.tar.gz: 056e886c4d5146019525d9aa5eb25e2f4e195dfee69abf9105be266210ca6e20daee3f0b5a3be66ab390d30d5eb7506e83ac0cd0842e62242fd602ce3f0d5ce0
|
data/lib/aws-record.rb
CHANGED
@@ -28,6 +28,7 @@ module Aws
|
|
28
28
|
autoload :ModelAttributes, 'aws-record/record/model_attributes'
|
29
29
|
autoload :Query, 'aws-record/record/query'
|
30
30
|
autoload :SecondaryIndexes, 'aws-record/record/secondary_indexes'
|
31
|
+
autoload :TableConfig, 'aws-record/record/table_config'
|
31
32
|
autoload :TableMigration, 'aws-record/record/table_migration'
|
32
33
|
autoload :VERSION, 'aws-record/record/version'
|
33
34
|
|
@@ -89,14 +89,17 @@ module Aws
|
|
89
89
|
private
|
90
90
|
def _migration_format_indexes(indexes)
|
91
91
|
return nil if indexes.empty?
|
92
|
-
indexes.collect do |name, opts|
|
92
|
+
mfi = indexes.collect do |name, opts|
|
93
93
|
h = { index_name: name }
|
94
94
|
h[:key_schema] = _si_key_schema(opts)
|
95
|
-
opts.delete(:hash_key)
|
96
|
-
opts.delete(:range_key)
|
95
|
+
hk = opts.delete(:hash_key)
|
96
|
+
rk = opts.delete(:range_key)
|
97
97
|
h = h.merge(opts)
|
98
|
+
opts[:hash_key] = hk if hk
|
99
|
+
opts[:range_key] = rk if rk
|
98
100
|
h
|
99
101
|
end
|
102
|
+
mfi
|
100
103
|
end
|
101
104
|
|
102
105
|
def _si_key_schema(opts)
|
@@ -0,0 +1,514 @@
|
|
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.
|
13
|
+
|
14
|
+
module Aws
|
15
|
+
module Record
|
16
|
+
|
17
|
+
# +Aws::Record::TableConfig+ provides a DSL for describing and modifying
|
18
|
+
# the remote configuration of your DynamoDB tables. A table configuration
|
19
|
+
# object can perform intelligent comparisons and incremental migrations
|
20
|
+
# versus the current remote configuration, if the table exists, or do a full
|
21
|
+
# create if it does not. In this manner, table configuration becomes fully
|
22
|
+
# declarative.
|
23
|
+
#
|
24
|
+
# @example A basic model with configuration.
|
25
|
+
# class Model
|
26
|
+
# include Aws::Record
|
27
|
+
# string_attr :uuid, hash_key: true
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# table_config = Aws::Record::TableConfig.define do |t|
|
31
|
+
# t.model_class Model
|
32
|
+
# t.read_capacity_units 10
|
33
|
+
# t.write_capacity_units 5
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# @example Running a conditional migration on a basic model.
|
37
|
+
# table_config = Aws::Record::TableConfig.define do |t|
|
38
|
+
# t.model_class Model
|
39
|
+
# t.read_capacity_units 10
|
40
|
+
# t.write_capacity_units 5
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# table_config.migrate! unless table_config.compatible?
|
44
|
+
#
|
45
|
+
# @example A model with a global secondary index.
|
46
|
+
# class Forum
|
47
|
+
# include Aws::Record
|
48
|
+
# string_attr :forum_uuid, hash_key: true
|
49
|
+
# integer_attr :post_id, range_key: true
|
50
|
+
# string_attr :post_title
|
51
|
+
# string_attr :post_body
|
52
|
+
# string_attr :author_username
|
53
|
+
# datetime_attr :created_date
|
54
|
+
# datetime_attr :updated_date
|
55
|
+
# string_set_attr :tags
|
56
|
+
# map_attr :metadata, default_value: {}
|
57
|
+
#
|
58
|
+
# global_secondary_index(
|
59
|
+
# :title,
|
60
|
+
# hash_key: :forum_uuid,
|
61
|
+
# range_key: :post_title,
|
62
|
+
# projection_type: "ALL"
|
63
|
+
# )
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# table_config = Aws::Record::TableConfig.define do |t|
|
67
|
+
# t.model_class Forum
|
68
|
+
# t.read_capacity_units 10
|
69
|
+
# t.write_capacity_units 5
|
70
|
+
#
|
71
|
+
# t.global_secondary_index(:title) do |i|
|
72
|
+
# i.read_capacity_units 5
|
73
|
+
# i.write_capacity_units 5
|
74
|
+
# end
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
class TableConfig
|
78
|
+
|
79
|
+
attr_accessor :client
|
80
|
+
|
81
|
+
class << self
|
82
|
+
|
83
|
+
# Creates a new table configuration, using a DSL in the provided block.
|
84
|
+
# The DSL has the following methods:
|
85
|
+
# * +#model_class+ A class name reference to the +Aws::Record+ model
|
86
|
+
# class.
|
87
|
+
# * +#read_capacity_units+ Sets the read capacity units for the table.
|
88
|
+
# * +#write_capacity_units+ Sets the write capacity units for the table.
|
89
|
+
# * +#global_secondary_index(index_symbol, &block)+ Defines a global
|
90
|
+
# secondary index with capacity attributes in a block:
|
91
|
+
# * +#read_capacity_units+ Sets the read capacity units for the
|
92
|
+
# index.
|
93
|
+
# * +#write_capacity_units+ Sets the write capacity units for the
|
94
|
+
# index.
|
95
|
+
#
|
96
|
+
# @example Defining a migration with a GSI.
|
97
|
+
# class Forum
|
98
|
+
# include Aws::Record
|
99
|
+
# string_attr :forum_uuid, hash_key: true
|
100
|
+
# integer_attr :post_id, range_key: true
|
101
|
+
# string_attr :post_title
|
102
|
+
# string_attr :post_body
|
103
|
+
# string_attr :author_username
|
104
|
+
# datetime_attr :created_date
|
105
|
+
# datetime_attr :updated_date
|
106
|
+
# string_set_attr :tags
|
107
|
+
# map_attr :metadata, default_value: {}
|
108
|
+
#
|
109
|
+
# global_secondary_index(
|
110
|
+
# :title,
|
111
|
+
# hash_key: :forum_uuid,
|
112
|
+
# range_key: :post_title,
|
113
|
+
# projection_type: "ALL"
|
114
|
+
# )
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# table_config = Aws::Record::TableConfig.define do |t|
|
118
|
+
# t.model_class Forum
|
119
|
+
# t.read_capacity_units 10
|
120
|
+
# t.write_capacity_units 5
|
121
|
+
#
|
122
|
+
# t.global_secondary_index(:title) do |i|
|
123
|
+
# i.read_capacity_units 5
|
124
|
+
# i.write_capacity_units 5
|
125
|
+
# end
|
126
|
+
# end
|
127
|
+
def define(&block)
|
128
|
+
cfg = TableConfig.new
|
129
|
+
cfg.instance_eval(&block)
|
130
|
+
cfg.configure_client
|
131
|
+
cfg
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# @api private
|
136
|
+
def initialize
|
137
|
+
@client_options = {}
|
138
|
+
@global_secondary_indexes = {}
|
139
|
+
end
|
140
|
+
|
141
|
+
# @api private
|
142
|
+
def model_class(model)
|
143
|
+
@model_class = model
|
144
|
+
end
|
145
|
+
|
146
|
+
# @api private
|
147
|
+
def read_capacity_units(units)
|
148
|
+
@read_capacity_units = units
|
149
|
+
end
|
150
|
+
|
151
|
+
# @api private
|
152
|
+
def write_capacity_units(units)
|
153
|
+
@write_capacity_units = units
|
154
|
+
end
|
155
|
+
|
156
|
+
# @api private
|
157
|
+
def global_secondary_index(name, &block)
|
158
|
+
gsi = GlobalSecondaryIndex.new
|
159
|
+
gsi.instance_eval(&block)
|
160
|
+
@global_secondary_indexes[name] = gsi
|
161
|
+
end
|
162
|
+
|
163
|
+
# @api private
|
164
|
+
def client_options(opts)
|
165
|
+
@client_options = opts
|
166
|
+
end
|
167
|
+
|
168
|
+
# @api private
|
169
|
+
def configure_client
|
170
|
+
@client = Aws::DynamoDB::Client.new(@client_options)
|
171
|
+
end
|
172
|
+
|
173
|
+
# Performs a migration, if needed, against the remote table. If
|
174
|
+
# +#compatible?+ would return true, the remote table already has the same
|
175
|
+
# throughput, key schema, attribute definitions, and global secondary
|
176
|
+
# indexes, so no further API calls are made. Otherwise, a DynamoDB table
|
177
|
+
# will be created or updated to match your declared configuration.
|
178
|
+
def migrate!
|
179
|
+
_validate_required_configuration
|
180
|
+
begin
|
181
|
+
resp = @client.describe_table(table_name: @model_class.table_name)
|
182
|
+
if _compatible_check(resp)
|
183
|
+
nil
|
184
|
+
else
|
185
|
+
# Gotcha: You need separate migrations for indexes and throughput
|
186
|
+
unless _throughput_equal(resp)
|
187
|
+
@client.update_table(
|
188
|
+
table_name: @model_class.table_name,
|
189
|
+
provisioned_throughput: {
|
190
|
+
read_capacity_units: @read_capacity_units,
|
191
|
+
write_capacity_units: @write_capacity_units
|
192
|
+
}
|
193
|
+
)
|
194
|
+
@client.wait_until(
|
195
|
+
:table_exists,
|
196
|
+
table_name: @model_class.table_name
|
197
|
+
)
|
198
|
+
end
|
199
|
+
unless _gsi_superset(resp)
|
200
|
+
@client.update_table(_update_index_opts(resp))
|
201
|
+
@client.wait_until(
|
202
|
+
:table_exists,
|
203
|
+
table_name: @model_class.table_name
|
204
|
+
)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
rescue DynamoDB::Errors::ResourceNotFoundException
|
208
|
+
# Code Smell: Exception as control flow.
|
209
|
+
# Can I use SDK ability to skip raising an exception for this?
|
210
|
+
@client.create_table(_create_table_opts)
|
211
|
+
@client.wait_until(:table_exists, table_name: @model_class.table_name)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Checks the remote table for compatibility. Similar to +#exact_match?+,
|
216
|
+
# this will return +false+ if the remote table does not exist. It also
|
217
|
+
# checks the keys, declared global secondary indexes, declared attribute
|
218
|
+
# definitions, and throughput for exact matches. However, if the remote
|
219
|
+
# end has additional attribute definitions and global secondary indexes
|
220
|
+
# not defined in your config, will still return +true+. This allows for a
|
221
|
+
# check that is friendly to single table inheritance use cases.
|
222
|
+
#
|
223
|
+
# @return [Boolean] true if remote is compatible, false otherwise.
|
224
|
+
def compatible?
|
225
|
+
begin
|
226
|
+
resp = @client.describe_table(table_name: @model_class.table_name)
|
227
|
+
_compatible_check(resp)
|
228
|
+
rescue DynamoDB::Errors::ResourceNotFoundException
|
229
|
+
false
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Checks against the remote table's configuration. If the remote table
|
234
|
+
# does not exist, guaranteed +false+. Otherwise, will check if the remote
|
235
|
+
# throughput, keys, attribute definitions, and global secondary indexes
|
236
|
+
# are exactly equal to your declared configuration.
|
237
|
+
#
|
238
|
+
# @return [Boolean] true if remote is an exact match, false otherwise.
|
239
|
+
def exact_match?
|
240
|
+
begin
|
241
|
+
resp = @client.describe_table(table_name: @model_class.table_name)
|
242
|
+
_throughput_equal(resp) &&
|
243
|
+
_keys_equal(resp) &&
|
244
|
+
_ad_equal(resp) &&
|
245
|
+
_gsi_equal(resp)
|
246
|
+
rescue DynamoDB::Errors::ResourceNotFoundException
|
247
|
+
false
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
private
|
252
|
+
def _compatible_check(resp)
|
253
|
+
_throughput_equal(resp) &&
|
254
|
+
_keys_equal(resp) &&
|
255
|
+
_ad_superset(resp) &&
|
256
|
+
_gsi_superset(resp)
|
257
|
+
end
|
258
|
+
|
259
|
+
def _create_table_opts
|
260
|
+
opts = {
|
261
|
+
table_name: @model_class.table_name,
|
262
|
+
provisioned_throughput: {
|
263
|
+
read_capacity_units: @read_capacity_units,
|
264
|
+
write_capacity_units: @write_capacity_units
|
265
|
+
}
|
266
|
+
}
|
267
|
+
opts[:key_schema] = _key_schema
|
268
|
+
opts[:attribute_definitions] = _attribute_definitions
|
269
|
+
gsi = _global_secondary_indexes
|
270
|
+
unless gsi.empty?
|
271
|
+
opts[:global_secondary_indexes] = gsi
|
272
|
+
end
|
273
|
+
opts
|
274
|
+
end
|
275
|
+
|
276
|
+
def _update_index_opts(resp)
|
277
|
+
gsi_updates, attribute_definitions = _gsi_updates(resp)
|
278
|
+
opts = {
|
279
|
+
table_name: @model_class.table_name,
|
280
|
+
global_secondary_index_updates: gsi_updates
|
281
|
+
}
|
282
|
+
unless attribute_definitions.empty?
|
283
|
+
opts[:attribute_definitions] = attribute_definitions
|
284
|
+
end
|
285
|
+
opts
|
286
|
+
end
|
287
|
+
|
288
|
+
def _gsi_updates(resp)
|
289
|
+
gsi_updates = []
|
290
|
+
attributes_referenced = Set.new
|
291
|
+
remote_gsis = resp.table.global_secondary_indexes
|
292
|
+
local_gsis = _global_secondary_indexes
|
293
|
+
remote_idx, local_idx = _gsi_index_names(remote_gsis, local_gsis)
|
294
|
+
create_candidates = local_idx - remote_idx
|
295
|
+
update_candidates = local_idx.intersection(remote_idx)
|
296
|
+
create_candidates.each do |index_name|
|
297
|
+
gsi = @model_class.global_secondary_indexes_for_migration.find do |i|
|
298
|
+
i[:index_name].to_s == index_name
|
299
|
+
end
|
300
|
+
gsi[:key_schema].each do |k|
|
301
|
+
attributes_referenced.add(k[:attribute_name])
|
302
|
+
end
|
303
|
+
# This may be a problem, check if I can maintain symbols.
|
304
|
+
lgsi = @global_secondary_indexes[index_name.to_sym]
|
305
|
+
gsi[:provisioned_throughput] = lgsi.provisioned_throughput
|
306
|
+
gsi_updates << {
|
307
|
+
create: gsi
|
308
|
+
}
|
309
|
+
end
|
310
|
+
update_candidates.each do |index_name|
|
311
|
+
# This may be a problem, check if I can maintain symbols.
|
312
|
+
lgsi = @global_secondary_indexes[index_name.to_sym]
|
313
|
+
gsi_updates << {
|
314
|
+
update: {
|
315
|
+
index_name: index_name,
|
316
|
+
provisioned_throughput: lgsi.provisioned_throughput
|
317
|
+
}
|
318
|
+
}
|
319
|
+
end
|
320
|
+
attribute_definitions = _attribute_definitions
|
321
|
+
incremental_attributes = attributes_referenced.map do |attr_name|
|
322
|
+
attribute_definitions.find do |ad|
|
323
|
+
ad[:attribute_name] == attr_name
|
324
|
+
end
|
325
|
+
end
|
326
|
+
[gsi_updates, incremental_attributes]
|
327
|
+
end
|
328
|
+
|
329
|
+
def _key_schema
|
330
|
+
_keys.map do |type, attr|
|
331
|
+
{
|
332
|
+
attribute_name: attr.database_name,
|
333
|
+
key_type: type == :hash ? "HASH" : "RANGE"
|
334
|
+
}
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def _attribute_definitions
|
339
|
+
attribute_definitions = _keys.map do |type, attr|
|
340
|
+
{
|
341
|
+
attribute_name: attr.database_name,
|
342
|
+
attribute_type: attr.dynamodb_type
|
343
|
+
}
|
344
|
+
end
|
345
|
+
@model_class.global_secondary_indexes.each do |_, attributes|
|
346
|
+
gsi_keys = [attributes[:hash_key]]
|
347
|
+
gsi_keys << attributes[:range_key] if attributes[:range_key]
|
348
|
+
gsi_keys.each do |name|
|
349
|
+
attribute = @model_class.attributes.attribute_for(name)
|
350
|
+
exists = attribute_definitions.any? do |ad|
|
351
|
+
ad[:attribute_name] == attribute.database_name
|
352
|
+
end
|
353
|
+
unless exists
|
354
|
+
attribute_definitions << {
|
355
|
+
attribute_name: attribute.database_name,
|
356
|
+
attribute_type: attribute.dynamodb_type
|
357
|
+
}
|
358
|
+
end
|
359
|
+
end
|
360
|
+
end
|
361
|
+
attribute_definitions
|
362
|
+
end
|
363
|
+
|
364
|
+
def _keys
|
365
|
+
@model_class.keys.inject({}) do |acc, (type, name)|
|
366
|
+
acc[type] = @model_class.attributes.attribute_for(name)
|
367
|
+
acc
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
def _throughput_equal(resp)
|
372
|
+
expected = resp.table.provisioned_throughput.to_h
|
373
|
+
actual = {
|
374
|
+
read_capacity_units: @read_capacity_units,
|
375
|
+
write_capacity_units: @write_capacity_units
|
376
|
+
}
|
377
|
+
actual.all? do |k,v|
|
378
|
+
expected[k] == v
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def _keys_equal(resp)
|
383
|
+
remote_key_schema = resp.table.key_schema.map { |i| i.to_h }
|
384
|
+
_array_unsorted_eql(remote_key_schema, _key_schema)
|
385
|
+
end
|
386
|
+
|
387
|
+
def _ad_equal(resp)
|
388
|
+
remote_ad = resp.table.attribute_definitions.map { |i| i.to_h }
|
389
|
+
_array_unsorted_eql(remote_ad, _attribute_definitions)
|
390
|
+
end
|
391
|
+
|
392
|
+
def _ad_superset(resp)
|
393
|
+
remote_ad = resp.table.attribute_definitions.map { |i| i.to_h }
|
394
|
+
_attribute_definitions.all? do |attribute_definition|
|
395
|
+
remote_ad.include?(attribute_definition)
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
def _gsi_superset(resp)
|
400
|
+
remote_gsis = resp.table.global_secondary_indexes
|
401
|
+
local_gsis = _global_secondary_indexes
|
402
|
+
remote_idx, local_idx = _gsi_index_names(remote_gsis, local_gsis)
|
403
|
+
if local_idx.subset?(remote_idx)
|
404
|
+
_gsi_set_compare(remote_gsis, local_gsis)
|
405
|
+
else
|
406
|
+
# If we have any local indexes not on the remote table,
|
407
|
+
# guaranteed false.
|
408
|
+
false
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def _gsi_equal(resp)
|
413
|
+
remote_gsis = resp.table.global_secondary_indexes
|
414
|
+
local_gsis = _global_secondary_indexes
|
415
|
+
remote_idx, local_idx = _gsi_index_names(remote_gsis, local_gsis)
|
416
|
+
if local_idx == remote_idx
|
417
|
+
_gsi_set_compare(remote_gsis, local_gsis)
|
418
|
+
else
|
419
|
+
false
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def _gsi_set_compare(remote_gsis, local_gsis)
|
424
|
+
local_gsis.all? do |lgsi|
|
425
|
+
rgsi = remote_gsis.find do |r|
|
426
|
+
r.index_name == lgsi[:index_name].to_s
|
427
|
+
end
|
428
|
+
|
429
|
+
remote_key_schema = rgsi.key_schema.map { |i| i.to_h }
|
430
|
+
ks_match = _array_unsorted_eql(remote_key_schema, lgsi[:key_schema])
|
431
|
+
|
432
|
+
rpt = rgsi.provisioned_throughput.to_h
|
433
|
+
lpt = lgsi[:provisioned_throughput]
|
434
|
+
pt_match = lpt.all? do |k,v|
|
435
|
+
rpt[k] == v
|
436
|
+
end
|
437
|
+
|
438
|
+
rp = rgsi.projection.to_h
|
439
|
+
lp = lgsi[:projection]
|
440
|
+
rp[:non_key_attributes].sort! if rp[:non_key_attributes]
|
441
|
+
lp[:non_key_attributes].sort! if lp[:non_key_attributes]
|
442
|
+
p_match = rp == lp
|
443
|
+
|
444
|
+
ks_match && pt_match && p_match
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
def _gsi_index_names(remote, local)
|
449
|
+
remote_index_names = Set.new
|
450
|
+
local_index_names = Set.new
|
451
|
+
if remote
|
452
|
+
remote.each do |gsi|
|
453
|
+
remote_index_names.add(gsi.index_name)
|
454
|
+
end
|
455
|
+
end
|
456
|
+
if local
|
457
|
+
local.each do |gsi|
|
458
|
+
local_index_names.add(gsi[:index_name].to_s)
|
459
|
+
end
|
460
|
+
end
|
461
|
+
[remote_index_names, local_index_names]
|
462
|
+
end
|
463
|
+
|
464
|
+
def _global_secondary_indexes
|
465
|
+
gsis = []
|
466
|
+
model_gsis = @model_class.global_secondary_indexes_for_migration
|
467
|
+
gsi_config = @global_secondary_indexes
|
468
|
+
if model_gsis
|
469
|
+
model_gsis.each do |mgsi|
|
470
|
+
config = gsi_config[mgsi[:index_name]]
|
471
|
+
# Validate throughput exists? Validate each throughput is in model?
|
472
|
+
gsis << mgsi.merge(
|
473
|
+
provisioned_throughput: config.provisioned_throughput
|
474
|
+
)
|
475
|
+
end
|
476
|
+
end
|
477
|
+
gsis
|
478
|
+
end
|
479
|
+
|
480
|
+
def _array_unsorted_eql(a, b)
|
481
|
+
a.all? { |x| b.include?(x) } && b.all? { |x| a.include?(x) }
|
482
|
+
end
|
483
|
+
|
484
|
+
def _validate_required_configuration
|
485
|
+
missing_config = []
|
486
|
+
missing_config << 'model_class' unless @model_class
|
487
|
+
missing_config << 'read_capacity_units' unless @read_capacity_units
|
488
|
+
missing_config << 'write_capacity_units' unless @write_capacity_units
|
489
|
+
unless missing_config.empty?
|
490
|
+
msg = missing_config.join(', ')
|
491
|
+
raise Errors::MissingRequiredConfiguration, 'Missing: ' + msg
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
# @api private
|
496
|
+
class GlobalSecondaryIndex
|
497
|
+
attr_reader :provisioned_throughput
|
498
|
+
|
499
|
+
def initialize
|
500
|
+
@provisioned_throughput = {}
|
501
|
+
end
|
502
|
+
|
503
|
+
def read_capacity_units(units)
|
504
|
+
@provisioned_throughput[:read_capacity_units] = units
|
505
|
+
end
|
506
|
+
|
507
|
+
def write_capacity_units(units)
|
508
|
+
@provisioned_throughput[:write_capacity_units] = units
|
509
|
+
end
|
510
|
+
end
|
511
|
+
|
512
|
+
end
|
513
|
+
end
|
514
|
+
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: 1.0
|
4
|
+
version: 1.1.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:
|
11
|
+
date: 2017-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-resources
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/aws-record/record/model_attributes.rb
|
55
55
|
- lib/aws-record/record/query.rb
|
56
56
|
- lib/aws-record/record/secondary_indexes.rb
|
57
|
+
- lib/aws-record/record/table_config.rb
|
57
58
|
- lib/aws-record/record/table_migration.rb
|
58
59
|
- lib/aws-record/record/version.rb
|
59
60
|
homepage: http://github.com/aws/aws-sdk-ruby-record
|