aws-record 2.11.0 → 2.13.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 +84 -19
- data/VERSION +1 -1
- data/lib/aws-record/record/attribute.rb +4 -2
- data/lib/aws-record/record/batch_read.rb +8 -13
- data/lib/aws-record/record/batch_write.rb +2 -1
- data/lib/aws-record/record/buildable_search.rb +15 -20
- data/lib/aws-record/record/client_configuration.rb +7 -7
- data/lib/aws-record/record/dirty_tracking.rb +3 -11
- data/lib/aws-record/record/errors.rb +18 -1
- data/lib/aws-record/record/item_collection.rb +5 -5
- data/lib/aws-record/record/item_data.rb +10 -11
- data/lib/aws-record/record/item_operations.rb +128 -96
- data/lib/aws-record/record/marshalers/boolean_marshaler.rb +4 -4
- data/lib/aws-record/record/marshalers/date_marshaler.rb +1 -3
- data/lib/aws-record/record/marshalers/date_time_marshaler.rb +1 -3
- data/lib/aws-record/record/marshalers/epoch_time_marshaler.rb +2 -6
- data/lib/aws-record/record/marshalers/float_marshaler.rb +4 -4
- data/lib/aws-record/record/marshalers/integer_marshaler.rb +4 -4
- data/lib/aws-record/record/marshalers/list_marshaler.rb +6 -6
- data/lib/aws-record/record/marshalers/map_marshaler.rb +6 -6
- data/lib/aws-record/record/marshalers/numeric_set_marshaler.rb +7 -7
- data/lib/aws-record/record/marshalers/string_marshaler.rb +3 -1
- data/lib/aws-record/record/marshalers/string_set_marshaler.rb +6 -6
- data/lib/aws-record/record/marshalers/time_marshaler.rb +1 -3
- data/lib/aws-record/record/model_attributes.rb +14 -16
- data/lib/aws-record/record/query.rb +4 -4
- data/lib/aws-record/record/secondary_indexes.rb +22 -25
- data/lib/aws-record/record/table_config.rb +45 -56
- data/lib/aws-record/record/table_migration.rb +32 -36
- data/lib/aws-record/record/transactions.rb +15 -23
- data/lib/aws-record/record/version.rb +1 -1
- data/lib/aws-record/record.rb +8 -8
- metadata +4 -5
@@ -52,31 +52,29 @@ module Aws
|
|
52
52
|
end
|
53
53
|
|
54
54
|
def _validate_attr_name(name)
|
55
|
-
unless name.is_a?(Symbol)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
raise Errors::NameCollision, "Cannot overwrite existing attribute #{name}"
|
60
|
-
end
|
55
|
+
raise ArgumentError, 'Must use symbolized :name attribute.' unless name.is_a?(Symbol)
|
56
|
+
return unless @attributes[name]
|
57
|
+
|
58
|
+
raise Errors::NameCollision, "Cannot overwrite existing attribute #{name}"
|
61
59
|
end
|
62
60
|
|
63
61
|
def _check_if_reserved(name)
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
return unless @model_class.instance_methods.include?(name)
|
63
|
+
|
64
|
+
raise Errors::ReservedName, "Cannot name an attribute #{name}, that would collide with an " \
|
65
|
+
'existing instance method.'
|
68
66
|
end
|
69
67
|
|
70
68
|
def _check_for_naming_collisions(name, storage_name)
|
71
69
|
if @attributes[storage_name.to_sym]
|
72
|
-
raise Errors::NameCollision, "Custom storage name #{storage_name} already exists as an"\
|
73
|
-
"
|
70
|
+
raise Errors::NameCollision, "Custom storage name #{storage_name} already exists as an " \
|
71
|
+
"attribute name in #{@attributes}"
|
74
72
|
elsif @storage_attributes[name.to_s]
|
75
|
-
raise Errors::NameCollision, "Attribute name #{name} already exists as a custom storage"\
|
76
|
-
"
|
73
|
+
raise Errors::NameCollision, "Attribute name #{name} already exists as a custom storage " \
|
74
|
+
"name in #{@storage_attributes}"
|
77
75
|
elsif @storage_attributes[storage_name]
|
78
|
-
raise Errors::NameCollision, "Custom storage name #{storage_name} already in use in"\
|
79
|
-
"
|
76
|
+
raise Errors::NameCollision, "Custom storage name #{storage_name} already in use in " \
|
77
|
+
"#{@storage_attributes}"
|
80
78
|
|
81
79
|
end
|
82
80
|
end
|
@@ -10,7 +10,7 @@ module Aws
|
|
10
10
|
|
11
11
|
module QueryClassMethods
|
12
12
|
# This method calls
|
13
|
-
# {http://docs.aws.amazon.com/
|
13
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#query-instance_method
|
14
14
|
# Aws::DynamoDB::Client#query}, populating the +:table_name+ parameter from the model
|
15
15
|
# class, and combining this with the other parameters you provide.
|
16
16
|
#
|
@@ -44,7 +44,7 @@ module Aws
|
|
44
44
|
# end
|
45
45
|
#
|
46
46
|
# @param [Hash] opts options to pass on to the client call to +#query+.
|
47
|
-
# See the documentation above in the AWS SDK for Ruby
|
47
|
+
# See the documentation above in the AWS SDK for Ruby V3.
|
48
48
|
# @return [Aws::Record::ItemCollection] an enumerable collection of the
|
49
49
|
# query result.
|
50
50
|
def query(opts)
|
@@ -53,7 +53,7 @@ module Aws
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# This method calls
|
56
|
-
# {http://docs.aws.amazon.com/
|
56
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#scan-instance_method
|
57
57
|
# Aws::DynamoDB::Client#scan}, populating the +:table_name+ parameter from the model
|
58
58
|
# class, and combining this with the other parameters you provide.
|
59
59
|
#
|
@@ -82,7 +82,7 @@ module Aws
|
|
82
82
|
# end
|
83
83
|
#
|
84
84
|
# @param [Hash] opts options to pass on to the client call to +#scan+.
|
85
|
-
# See the documentation above in the AWS SDK for Ruby
|
85
|
+
# See the documentation above in the AWS SDK for Ruby V3.
|
86
86
|
# @return [Aws::Record::ItemCollection] an enumerable collection of the
|
87
87
|
# scan result.
|
88
88
|
def scan(opts = {})
|
@@ -30,11 +30,11 @@ module Aws
|
|
30
30
|
# @param [Symbol] name index name for this local secondary index
|
31
31
|
# @param [Hash] opts
|
32
32
|
# @option opts [Symbol] :range_key the range key used by this local
|
33
|
-
#
|
34
|
-
#
|
33
|
+
# secondary index. Note that the hash key MUST be the table's hash
|
34
|
+
# key, and so that value will be filled in for you.
|
35
35
|
# @option opts [Hash] :projection a hash which defines which attributes
|
36
|
-
#
|
37
|
-
#
|
36
|
+
# are copied from the table to the index. See shape details in the
|
37
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Types/Projection.html AWS SDK for Ruby V3 docs}.
|
38
38
|
def local_secondary_index(name, opts)
|
39
39
|
opts[:hash_key] = hash_key
|
40
40
|
_validate_required_lsi_keys(opts)
|
@@ -50,12 +50,12 @@ module Aws
|
|
50
50
|
# @param [Symbol] name index name for this global secondary index
|
51
51
|
# @param [Hash] opts
|
52
52
|
# @option opts [Symbol] :hash_key the hash key used by this global
|
53
|
-
#
|
53
|
+
# secondary index.
|
54
54
|
# @option opts [Symbol] :range_key the range key used by this global
|
55
|
-
#
|
55
|
+
# secondary index.
|
56
56
|
# @option opts [Hash] :projection a hash which defines which attributes
|
57
|
-
#
|
58
|
-
#
|
57
|
+
# are copied from the table to the index. See shape details in the
|
58
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Types/Projection.html AWS SDK for Ruby V3 docs}.
|
59
59
|
def global_secondary_index(name, opts)
|
60
60
|
_validate_required_gsi_keys(opts)
|
61
61
|
global_secondary_indexes[name] = opts
|
@@ -99,7 +99,8 @@ module Aws
|
|
99
99
|
|
100
100
|
def _migration_format_indexes(indexes)
|
101
101
|
return nil if indexes.empty?
|
102
|
-
|
102
|
+
|
103
|
+
indexes.collect do |name, opts|
|
103
104
|
h = { index_name: name }
|
104
105
|
h[:key_schema] = _si_key_schema(opts)
|
105
106
|
hk = opts.delete(:hash_key)
|
@@ -109,7 +110,6 @@ module Aws
|
|
109
110
|
opts[:range_key] = rk if rk
|
110
111
|
h
|
111
112
|
end
|
112
|
-
mfi
|
113
113
|
end
|
114
114
|
|
115
115
|
def _si_key_schema(opts)
|
@@ -127,22 +127,20 @@ module Aws
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def _validate_required_lsi_keys(params)
|
130
|
-
|
131
|
-
_validate_attributes_exist(params[:hash_key], params[:range_key])
|
132
|
-
else
|
130
|
+
unless params[:hash_key] && params[:range_key]
|
133
131
|
raise ArgumentError, 'Local Secondary Indexes require a hash and range key!'
|
134
132
|
end
|
133
|
+
|
134
|
+
_validate_attributes_exist(params[:hash_key], params[:range_key])
|
135
135
|
end
|
136
136
|
|
137
137
|
def _validate_required_gsi_keys(params)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
_validate_attributes_exist(params[:hash_key])
|
143
|
-
end
|
138
|
+
raise ArgumentError, 'Global Secondary Indexes require at least a hash key!' unless params[:hash_key]
|
139
|
+
|
140
|
+
if params[:range_key]
|
141
|
+
_validate_attributes_exist(params[:hash_key], params[:range_key])
|
144
142
|
else
|
145
|
-
|
143
|
+
_validate_attributes_exist(params[:hash_key])
|
146
144
|
end
|
147
145
|
end
|
148
146
|
|
@@ -150,12 +148,11 @@ module Aws
|
|
150
148
|
missing = attr_names.reject do |attr_name|
|
151
149
|
@attributes.present?(attr_name)
|
152
150
|
end
|
153
|
-
|
154
|
-
raise ArgumentError, "#{missing.join(', ')} not present in model attributes."\
|
155
|
-
' Please ensure that attributes are defined in the model'\
|
156
|
-
' class BEFORE defining an index on those attributes.'
|
151
|
+
return if missing.empty?
|
157
152
|
|
158
|
-
|
153
|
+
raise ArgumentError, "#{missing.join(', ')} not present in model attributes. " \
|
154
|
+
'Please ensure that attributes are defined in the model ' \
|
155
|
+
'class BEFORE defining an index on those attributes.'
|
159
156
|
end
|
160
157
|
end
|
161
158
|
end
|
@@ -194,11 +194,9 @@ module Aws
|
|
194
194
|
# @api private
|
195
195
|
def ttl_attribute(attribute_symbol)
|
196
196
|
attribute = @model_class.attributes.attribute_for(attribute_symbol)
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
raise ArgumentError, "Invalid attribute #{attribute_symbol} for #{@model_class}"
|
201
|
-
end
|
197
|
+
raise ArgumentError, "Invalid attribute #{attribute_symbol} for #{@model_class}" unless attribute
|
198
|
+
|
199
|
+
@ttl_attribute = attribute.database_name
|
202
200
|
end
|
203
201
|
|
204
202
|
# @api private
|
@@ -245,17 +243,18 @@ module Aws
|
|
245
243
|
# First up is TTL attribute. Since this migration is not exact match,
|
246
244
|
# we will only alter TTL status if we have a TTL attribute defined. We
|
247
245
|
# may someday support explicit TTL deletion, but we do not yet do this.
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
246
|
+
return unless @ttl_attribute
|
247
|
+
return if _ttl_compatibility_check
|
248
|
+
|
249
|
+
client.update_time_to_live(
|
250
|
+
table_name: @model_class.table_name,
|
251
|
+
time_to_live_specification: {
|
252
|
+
enabled: true,
|
253
|
+
attribute_name: @ttl_attribute
|
254
|
+
}
|
255
|
+
)
|
256
|
+
# Else TTL is compatible and we are done.
|
257
|
+
# Else our work is done.
|
259
258
|
end
|
260
259
|
|
261
260
|
# Checks the remote table for compatibility. Similar to +#exact_match?+,
|
@@ -382,7 +381,7 @@ module Aws
|
|
382
381
|
resp_gsis = resp.table.global_secondary_indexes
|
383
382
|
_add_global_secondary_index_throughput(opts, resp_gsis)
|
384
383
|
end
|
385
|
-
end
|
384
|
+
end
|
386
385
|
opts
|
387
386
|
elsif @billing_mode == 'PAY_PER_REQUEST'
|
388
387
|
{
|
@@ -400,9 +399,7 @@ module Aws
|
|
400
399
|
table_name: @model_class.table_name,
|
401
400
|
global_secondary_index_updates: gsi_updates
|
402
401
|
}
|
403
|
-
unless attribute_definitions.empty?
|
404
|
-
opts[:attribute_definitions] = attribute_definitions
|
405
|
-
end
|
402
|
+
opts[:attribute_definitions] = attribute_definitions unless attribute_definitions.empty?
|
406
403
|
opts
|
407
404
|
end
|
408
405
|
|
@@ -474,12 +471,12 @@ module Aws
|
|
474
471
|
exists = attribute_definitions.any? do |ad|
|
475
472
|
ad[:attribute_name] == attribute.database_name
|
476
473
|
end
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
474
|
+
next if exists
|
475
|
+
|
476
|
+
attribute_definitions << {
|
477
|
+
attribute_name: attribute.database_name,
|
478
|
+
attribute_type: attribute.dynamodb_type
|
479
|
+
}
|
483
480
|
end
|
484
481
|
end
|
485
482
|
attribute_definitions
|
@@ -566,15 +563,15 @@ module Aws
|
|
566
563
|
rpt[k] == v
|
567
564
|
end
|
568
565
|
elsif @billing_mode == 'PAY_PER_REQUEST'
|
569
|
-
pt_match = lpt.nil?
|
566
|
+
pt_match = lpt.nil?
|
570
567
|
else
|
571
568
|
raise ArgumentError, "Unsupported billing mode #{@billing_mode}"
|
572
569
|
end
|
573
570
|
|
574
571
|
rp = rgsi.projection.to_h
|
575
572
|
lp = lgsi[:projection]
|
576
|
-
rp[:non_key_attributes]
|
577
|
-
lp[:non_key_attributes]
|
573
|
+
rp[:non_key_attributes]&.sort!
|
574
|
+
lp[:non_key_attributes]&.sort!
|
578
575
|
p_match = rp == lp
|
579
576
|
|
580
577
|
ks_match && pt_match && p_match
|
@@ -584,15 +581,11 @@ module Aws
|
|
584
581
|
def _gsi_index_names(remote, local)
|
585
582
|
remote_index_names = Set.new
|
586
583
|
local_index_names = Set.new
|
587
|
-
|
588
|
-
|
589
|
-
remote_index_names.add(gsi.index_name)
|
590
|
-
end
|
584
|
+
remote&.each do |gsi|
|
585
|
+
remote_index_names.add(gsi.index_name)
|
591
586
|
end
|
592
|
-
|
593
|
-
|
594
|
-
local_index_names.add(gsi[:index_name].to_s)
|
595
|
-
end
|
587
|
+
local&.each do |gsi|
|
588
|
+
local_index_names.add(gsi[:index_name].to_s)
|
596
589
|
end
|
597
590
|
[remote_index_names, local_index_names]
|
598
591
|
end
|
@@ -601,17 +594,15 @@ module Aws
|
|
601
594
|
gsis = []
|
602
595
|
model_gsis = @model_class.global_secondary_indexes_for_migration
|
603
596
|
gsi_config = @global_secondary_indexes
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
end
|
614
|
-
end
|
597
|
+
model_gsis&.each do |mgsi|
|
598
|
+
config = gsi_config[mgsi[:index_name]]
|
599
|
+
gsis << if @billing_mode == 'PROVISIONED'
|
600
|
+
mgsi.merge(
|
601
|
+
provisioned_throughput: config.provisioned_throughput
|
602
|
+
)
|
603
|
+
else
|
604
|
+
mgsi
|
605
|
+
end
|
615
606
|
end
|
616
607
|
gsis
|
617
608
|
end
|
@@ -626,15 +617,13 @@ module Aws
|
|
626
617
|
if @billing_mode == 'PROVISIONED'
|
627
618
|
missing_config << 'read_capacity_units' unless @read_capacity_units
|
628
619
|
missing_config << 'write_capacity_units' unless @write_capacity_units
|
629
|
-
|
630
|
-
|
631
|
-
raise ArgumentError, "Cannot have billing mode #{@billing_mode} with provisioned capacity."
|
632
|
-
end
|
633
|
-
end
|
634
|
-
unless missing_config.empty?
|
635
|
-
msg = missing_config.join(', ')
|
636
|
-
raise Errors::MissingRequiredConfiguration, 'Missing: ' + msg
|
620
|
+
elsif @read_capacity_units || @write_capacity_units
|
621
|
+
raise ArgumentError, "Cannot have billing mode #{@billing_mode} with provisioned capacity."
|
637
622
|
end
|
623
|
+
return if missing_config.empty?
|
624
|
+
|
625
|
+
msg = missing_config.join(', ')
|
626
|
+
raise Errors::MissingRequiredConfiguration, "Missing: #{msg}"
|
638
627
|
end
|
639
628
|
|
640
629
|
# @api private
|
@@ -5,7 +5,7 @@ module Aws
|
|
5
5
|
class TableMigration
|
6
6
|
# @!attribute [rw] client
|
7
7
|
# @return [Aws::DynamoDB::Client] the
|
8
|
-
# {http://docs.aws.amazon.com/
|
8
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html Aws::DynamoDB::Client}
|
9
9
|
# class used by this table migration instance.
|
10
10
|
attr_accessor :client
|
11
11
|
|
@@ -13,7 +13,7 @@ module Aws
|
|
13
13
|
# @param [Hash] opts
|
14
14
|
# @option opts [Aws::DynamoDB::Client] :client Allows you to inject your
|
15
15
|
# own
|
16
|
-
# {http://docs.aws.amazon.com/
|
16
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html Aws::DynamoDB::Client}
|
17
17
|
# class. If this option is not included, a client will be constructed for
|
18
18
|
# you with default parameters.
|
19
19
|
def initialize(model, opts = {})
|
@@ -24,7 +24,7 @@ module Aws
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# This method calls
|
27
|
-
# {http://docs.aws.amazon.com/
|
27
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#create_table-instance_method
|
28
28
|
# Aws::DynamoDB::Client#create_table}, populating the attribute definitions and
|
29
29
|
# key schema based on your model class, as well as passing through other
|
30
30
|
# parameters as provided by you.
|
@@ -75,9 +75,9 @@ module Aws
|
|
75
75
|
end
|
76
76
|
if (gsis = @model.global_secondary_indexes_for_migration)
|
77
77
|
unless gsit || opts[:billing_mode] == 'PAY_PER_REQUEST'
|
78
|
-
raise ArgumentError, 'If you define global secondary indexes, you must also define'\
|
79
|
-
'
|
80
|
-
"
|
78
|
+
raise ArgumentError, 'If you define global secondary indexes, you must also define ' \
|
79
|
+
':global_secondary_index_throughput on table creation, ' \
|
80
|
+
"unless :billing_mode is set to 'PAY_PER_REQUEST'."
|
81
81
|
end
|
82
82
|
gsis_opts = if opts[:billing_mode] == 'PAY_PER_REQUEST'
|
83
83
|
gsis
|
@@ -91,7 +91,7 @@ module Aws
|
|
91
91
|
end
|
92
92
|
|
93
93
|
# This method calls
|
94
|
-
# {http://docs.aws.amazon.com/
|
94
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#update_table-instance_method
|
95
95
|
# Aws::DynamoDB::Client#update_table} using the parameters that you provide.
|
96
96
|
#
|
97
97
|
# @param [Hash] opts options to pass on to the client call to
|
@@ -109,7 +109,7 @@ module Aws
|
|
109
109
|
end
|
110
110
|
|
111
111
|
# This method calls
|
112
|
-
# {http://docs.aws.amazon.com/
|
112
|
+
# {http://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/DynamoDB/Client.html#delete_table-instance_method
|
113
113
|
# Aws::DynamoDB::Client#delete_table} using the table name of your model.
|
114
114
|
#
|
115
115
|
# @raise [Aws::Record::Errors::TableDoesNotExist] if the table did not
|
@@ -136,29 +136,25 @@ module Aws
|
|
136
136
|
end
|
137
137
|
|
138
138
|
def _assert_required_include(model)
|
139
|
-
|
140
|
-
|
141
|
-
|
139
|
+
return if model.include?(::Aws::Record)
|
140
|
+
|
141
|
+
raise Errors::InvalidModel, 'Table models must include Aws::Record'
|
142
142
|
end
|
143
143
|
|
144
144
|
def _validate_billing(opts)
|
145
145
|
valid_modes = %w[PAY_PER_REQUEST PROVISIONED]
|
146
|
-
if opts.key?(:billing_mode)
|
147
|
-
|
148
|
-
|
149
|
-
" current value is: #{opts[:billing_mode]}"
|
150
|
-
end
|
146
|
+
if opts.key?(:billing_mode) && !valid_modes.include?(opts[:billing_mode])
|
147
|
+
raise ArgumentError, ":billing_mode option must be one of #{valid_modes.join(', ')} " \
|
148
|
+
"current value is: #{opts[:billing_mode]}"
|
151
149
|
end
|
152
150
|
if opts.key?(:provisioned_throughput)
|
153
151
|
if opts[:billing_mode] == 'PAY_PER_REQUEST'
|
154
|
-
raise ArgumentError, 'when :provisioned_throughput option is specified, :billing_mode'\
|
155
|
-
"
|
156
|
-
end
|
157
|
-
else
|
158
|
-
if opts[:billing_mode] != 'PAY_PER_REQUEST'
|
159
|
-
raise ArgumentError, 'when :provisioned_throughput option is not specified,'\
|
160
|
-
" :billing_mode must be set to 'PAY_PER_REQUEST'"
|
152
|
+
raise ArgumentError, 'when :provisioned_throughput option is specified, :billing_mode ' \
|
153
|
+
"must either be unspecified or have a value of 'PROVISIONED'"
|
161
154
|
end
|
155
|
+
elsif opts[:billing_mode] != 'PAY_PER_REQUEST'
|
156
|
+
raise ArgumentError, 'when :provisioned_throughput option is not specified, ' \
|
157
|
+
":billing_mode must be set to 'PAY_PER_REQUEST'"
|
162
158
|
end
|
163
159
|
end
|
164
160
|
|
@@ -179,15 +175,15 @@ module Aws
|
|
179
175
|
exists = attr_def.find do |a|
|
180
176
|
a[:attribute_name] == key_schema[:attribute_name]
|
181
177
|
end
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
)
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
178
|
+
next if exists
|
179
|
+
|
180
|
+
attr = attributes.attribute_for(
|
181
|
+
attributes.db_to_attribute_name(key_schema[:attribute_name])
|
182
|
+
)
|
183
|
+
attr_def << {
|
184
|
+
attribute_name: attr.database_name,
|
185
|
+
attribute_type: attr.dynamodb_type
|
186
|
+
}
|
191
187
|
end
|
192
188
|
end
|
193
189
|
create_opts[:attribute_definitions] = attr_def
|
@@ -202,10 +198,10 @@ module Aws
|
|
202
198
|
params.merge(provisioned_throughput: throughput)
|
203
199
|
end
|
204
200
|
unless missing_throughput.empty?
|
205
|
-
raise ArgumentError, 'Missing provisioned throughput for the following global secondary'\
|
206
|
-
"
|
207
|
-
"
|
208
|
-
"
|
201
|
+
raise ArgumentError, 'Missing provisioned throughput for the following global secondary ' \
|
202
|
+
"indexes: #{missing_throughput.join(', ')}. GSIs: " \
|
203
|
+
"#{global_secondary_indexes} and defined throughput: " \
|
204
|
+
"#{gsi_throughput}"
|
209
205
|
end
|
210
206
|
ret
|
211
207
|
end
|
@@ -236,7 +236,7 @@ module Aws
|
|
236
236
|
elsif (check_record = item.delete(:check))
|
237
237
|
_transform_check_record(check_record, item)
|
238
238
|
else
|
239
|
-
raise ArgumentError, 'Invalid transact write item, must include an operation of '\
|
239
|
+
raise ArgumentError, 'Invalid transact write item, must include an operation of ' \
|
240
240
|
"type :save, :update, :delete, :update, or :check - #{item}"
|
241
241
|
|
242
242
|
end
|
@@ -250,13 +250,13 @@ module Aws
|
|
250
250
|
safety_expression = save_record.send(:prevent_overwrite_expression)
|
251
251
|
if opts.include?(:condition_expression)
|
252
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"\
|
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
260
|
"\tExtra Options: #{JSON.pretty_unparse(opts)}"
|
261
261
|
else
|
262
262
|
opts = opts.merge(safety_expression)
|
@@ -284,25 +284,17 @@ module Aws
|
|
284
284
|
def _transform_update_record(update_record, opts)
|
285
285
|
# extract dirty attribute changes to perform an update
|
286
286
|
opts[:table_name] = update_record.class.table_name
|
287
|
+
opts[:key] = update_record.send(:key_values)
|
287
288
|
dirty_changes = update_record.send(:_dirty_changes_for_update)
|
288
|
-
|
289
|
+
update_expression_opts = update_record.class.send(
|
289
290
|
:_build_update_expression,
|
290
291
|
dirty_changes
|
291
292
|
)
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
opts[:expression_attribute_names] = exp_attr_names.merge(names)
|
298
|
-
else
|
299
|
-
opts[:expression_attribute_names] = exp_attr_names
|
300
|
-
end
|
301
|
-
if (values = opts[:expression_attribute_values])
|
302
|
-
opts[:expression_attribute_values] = exp_attr_values.merge(values)
|
303
|
-
else
|
304
|
-
opts[:expression_attribute_values] = exp_attr_values
|
305
|
-
end
|
293
|
+
opts = update_record.class.send(
|
294
|
+
:_merge_update_expression_opts,
|
295
|
+
update_expression_opts,
|
296
|
+
opts
|
297
|
+
)
|
306
298
|
{ update: opts }
|
307
299
|
end
|
308
300
|
|
data/lib/aws-record/record.rb
CHANGED
@@ -117,14 +117,13 @@ module Aws
|
|
117
117
|
# MyOtherTable.table_name # => "test_MyTable"
|
118
118
|
def table_name
|
119
119
|
# rubocop:disable Style/RedundantSelf
|
120
|
-
@table_name ||=
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
end
|
120
|
+
@table_name ||= if Aws::Record.extends_record?(self) &&
|
121
|
+
default_table_name(self.superclass) != self.superclass.table_name
|
122
|
+
self.superclass.instance_variable_get('@table_name')
|
123
|
+
else
|
124
|
+
default_table_name(self)
|
125
|
+
end
|
126
|
+
|
128
127
|
# rubocop:enable Style/RedundantSelf
|
129
128
|
end
|
130
129
|
|
@@ -247,6 +246,7 @@ module Aws
|
|
247
246
|
|
248
247
|
def default_table_name(klass)
|
249
248
|
return unless klass.name
|
249
|
+
|
250
250
|
klass.name.split('::').join('_')
|
251
251
|
end
|
252
252
|
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.13.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-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-dynamodb
|
@@ -32,8 +32,7 @@ dependencies:
|
|
32
32
|
version: 1.85.0
|
33
33
|
description: Provides an object mapping abstraction for Amazon DynamoDB.
|
34
34
|
email:
|
35
|
-
-
|
36
|
-
- alexwoo@amazon.com
|
35
|
+
- aws-dr-rubygems@amazon.com
|
37
36
|
executables: []
|
38
37
|
extensions: []
|
39
38
|
extra_rdoc_files: []
|
@@ -87,7 +86,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
87
86
|
requirements:
|
88
87
|
- - ">="
|
89
88
|
- !ruby/object:Gem::Version
|
90
|
-
version: '
|
89
|
+
version: '2.3'
|
91
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
91
|
requirements:
|
93
92
|
- - ">="
|