aws-record 2.4.0 → 2.6.1
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 +5 -5
- data/lib/aws-record/record.rb +5 -2
- data/lib/aws-record/record/attribute.rb +8 -4
- data/lib/aws-record/record/buildable_search.rb +60 -15
- data/lib/aws-record/record/item_collection.rb +5 -2
- data/lib/aws-record/record/item_data.rb +2 -2
- data/lib/aws-record/record/item_operations.rb +1 -2
- data/lib/aws-record/record/marshalers/numeric_set_marshaler.rb +1 -1
- data/lib/aws-record/record/table_migration.rb +50 -9
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 613ebc2bb79fb30645f69fc831911f4fb269e9fe1e0d69bb064e5cc0b6c3294c
|
4
|
+
data.tar.gz: 6012bd27fd72dd5b8702e9833d302c57df7d9c44834ac37a6f347735328898ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e524df13f1433045d958466a377672f28a9c5cb7765f1d365ba856ff51ad8b78d7ab60bf55bd4b36d36ed4d880f7452ee5f09aff9cf0f7ec67f1096dbb3ccc2a
|
7
|
+
data.tar.gz: 34bb9db197f9f6b825b1b4296aace9df35f1e72f9e814bc530b25e36117500ab52b2710730ebf3dd712381fb7d85415f36a52a61c1c32420922492d3ebf21729
|
data/lib/aws-record/record.rb
CHANGED
@@ -50,7 +50,6 @@ module Aws
|
|
50
50
|
# # Attribute definitions go here...
|
51
51
|
# end
|
52
52
|
def self.included(sub_class)
|
53
|
-
@track_mutations = true
|
54
53
|
sub_class.send(:extend, RecordClassMethods)
|
55
54
|
sub_class.send(:include, Attributes)
|
56
55
|
sub_class.send(:include, ItemOperations)
|
@@ -201,7 +200,11 @@ module Aws
|
|
201
200
|
# @return [Boolean] true if mutation tracking is enabled at the model
|
202
201
|
# level, false otherwise.
|
203
202
|
def mutation_tracking_enabled?
|
204
|
-
@track_mutations
|
203
|
+
if defined?(@track_mutations)
|
204
|
+
@track_mutations
|
205
|
+
else
|
206
|
+
@track_mutations = true
|
207
|
+
end
|
205
208
|
end
|
206
209
|
|
207
210
|
def model_valid?
|
@@ -48,12 +48,12 @@ module Aws
|
|
48
48
|
# item is nil or not set at persistence time.
|
49
49
|
def initialize(name, options = {})
|
50
50
|
@name = name
|
51
|
-
@database_name = options[:database_attribute_name]
|
51
|
+
@database_name = (options[:database_attribute_name] || name).to_s
|
52
52
|
@dynamodb_type = options[:dynamodb_type]
|
53
53
|
@marshaler = options[:marshaler] || DefaultMarshaler
|
54
54
|
@persist_nil = options[:persist_nil]
|
55
55
|
dv = options[:default_value]
|
56
|
-
@default_value_or_lambda =
|
56
|
+
@default_value_or_lambda = _is_lambda?(dv) ? dv : type_cast(dv)
|
57
57
|
end
|
58
58
|
|
59
59
|
# Attempts to type cast a raw value into the attribute's type. This call
|
@@ -92,8 +92,8 @@ module Aws
|
|
92
92
|
|
93
93
|
# @api private
|
94
94
|
def default_value
|
95
|
-
if @default_value_or_lambda
|
96
|
-
@default_value_or_lambda.call
|
95
|
+
if _is_lambda?(@default_value_or_lambda)
|
96
|
+
type_cast(@default_value_or_lambda.call)
|
97
97
|
else
|
98
98
|
_deep_copy(@default_value_or_lambda)
|
99
99
|
end
|
@@ -104,6 +104,10 @@ module Aws
|
|
104
104
|
Marshal.load(Marshal.dump(obj))
|
105
105
|
end
|
106
106
|
|
107
|
+
def _is_lambda?(obj)
|
108
|
+
obj.respond_to?(:call)
|
109
|
+
end
|
110
|
+
|
107
111
|
end
|
108
112
|
|
109
113
|
# This is an identity marshaler, which performs no changes for type casting
|
@@ -101,9 +101,9 @@ module Aws
|
|
101
101
|
@params[:expression_attribute_values] = {}
|
102
102
|
values = @params[:expression_attribute_values]
|
103
103
|
end
|
104
|
-
_key_pass(statement_str, names)
|
105
|
-
_apply_values(
|
106
|
-
@params[:key_condition_expression] =
|
104
|
+
prepared = _key_pass(statement_str, names)
|
105
|
+
statement = _apply_values(prepared, subs, values)
|
106
|
+
@params[:key_condition_expression] = statement
|
107
107
|
self
|
108
108
|
end
|
109
109
|
|
@@ -123,7 +123,7 @@ module Aws
|
|
123
123
|
# "contains(:body, ?)",
|
124
124
|
# "bacon"
|
125
125
|
# ).complete!
|
126
|
-
#
|
126
|
+
#
|
127
127
|
def filter_expr(statement_str, *subs)
|
128
128
|
names = @params[:expression_attribute_names]
|
129
129
|
if names.nil?
|
@@ -135,9 +135,9 @@ module Aws
|
|
135
135
|
@params[:expression_attribute_values] = {}
|
136
136
|
values = @params[:expression_attribute_values]
|
137
137
|
end
|
138
|
-
_key_pass(statement_str, names)
|
139
|
-
_apply_values(
|
140
|
-
@params[:filter_expression] =
|
138
|
+
prepared = _key_pass(statement_str, names)
|
139
|
+
statement = _apply_values(prepared, subs, values)
|
140
|
+
@params[:filter_expression] = statement
|
141
141
|
self
|
142
142
|
end
|
143
143
|
|
@@ -167,8 +167,8 @@ module Aws
|
|
167
167
|
@params[:expression_attribute_names] = {}
|
168
168
|
names = @params[:expression_attribute_names]
|
169
169
|
end
|
170
|
-
_key_pass(statement_str, names)
|
171
|
-
@params[:projection_expression] =
|
170
|
+
prepared = _key_pass(statement_str, names)
|
171
|
+
@params[:projection_expression] = prepared
|
172
172
|
self
|
173
173
|
end
|
174
174
|
|
@@ -178,6 +178,50 @@ module Aws
|
|
178
178
|
self
|
179
179
|
end
|
180
180
|
|
181
|
+
# Allows you to define a callback that will determine the model class
|
182
|
+
# to be used for each item, allowing queries to return an ItemCollection
|
183
|
+
# with mixed models. The provided block must return the model class based on
|
184
|
+
# any logic on the raw item attributes or `nil` if no model applies and
|
185
|
+
# the item should be skipped. Note: The block only has access to raw item
|
186
|
+
# data so attributes must be accessed using their names as defined in the
|
187
|
+
# table, not as the symbols defined in the model class(s).
|
188
|
+
#
|
189
|
+
# @example Scan with heterogeneous results:
|
190
|
+
# # Example model classes
|
191
|
+
# class Model_A
|
192
|
+
# include Aws::Record
|
193
|
+
# set_table_name(TABLE_NAME)
|
194
|
+
#
|
195
|
+
# string_attr :uuid, hash_key: true
|
196
|
+
# string_attr :class_name, range_key: true
|
197
|
+
#
|
198
|
+
# string_attr :attr_a
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# class Model_B
|
202
|
+
# include Aws::Record
|
203
|
+
# set_table_name(TABLE_NAME)
|
204
|
+
#
|
205
|
+
# string_attr :uuid, hash_key: true
|
206
|
+
# string_attr :class_name, range_key: true
|
207
|
+
#
|
208
|
+
# string_attr :attr_b
|
209
|
+
# end
|
210
|
+
#
|
211
|
+
# # use multi_model_filter to create a query on TABLE_NAME
|
212
|
+
# items = Model_A.build_scan.multi_model_filter do |raw_item_attributes|
|
213
|
+
# case raw_item_attributes['class_name']
|
214
|
+
# when "A" then Model_A
|
215
|
+
# when "B" then Model_B
|
216
|
+
# else
|
217
|
+
# nil
|
218
|
+
# end
|
219
|
+
# end.complete!
|
220
|
+
def multi_model_filter(proc = nil, &block)
|
221
|
+
@params[:model_filter] = proc || block
|
222
|
+
self
|
223
|
+
end
|
224
|
+
|
181
225
|
# You must call this method at the end of any query or scan you build.
|
182
226
|
#
|
183
227
|
# @return [Aws::Record::ItemCollection] The item collection lazy
|
@@ -188,8 +232,8 @@ module Aws
|
|
188
232
|
|
189
233
|
private
|
190
234
|
def _key_pass(statement, names)
|
191
|
-
statement.gsub
|
192
|
-
key = match.gsub
|
235
|
+
statement.gsub(/:(\w+)/) do |match|
|
236
|
+
key = match.gsub(':','').to_sym
|
193
237
|
key_name = @model.attributes.storage_name_for(key)
|
194
238
|
if key_name
|
195
239
|
sub_name = _next_name
|
@@ -204,15 +248,16 @@ module Aws
|
|
204
248
|
|
205
249
|
def _apply_values(statement, subs, values)
|
206
250
|
count = 0
|
207
|
-
statement.gsub
|
251
|
+
statement.gsub(/[?]/) do |match|
|
208
252
|
sub_value = _next_value
|
209
253
|
raise "Substitution collision!" if values[sub_value]
|
210
254
|
values[sub_value] = subs[count]
|
211
255
|
count += 1
|
212
256
|
sub_value
|
213
|
-
end
|
214
|
-
|
215
|
-
|
257
|
+
end.tap do
|
258
|
+
unless count == subs.size
|
259
|
+
raise "Expected #{count} values in the substitution set, but found #{subs.size}"
|
260
|
+
end
|
216
261
|
end
|
217
262
|
end
|
218
263
|
|
@@ -19,6 +19,7 @@ module Aws
|
|
19
19
|
def initialize(search_method, search_params, model, client)
|
20
20
|
@search_method = search_method
|
21
21
|
@search_params = search_params
|
22
|
+
@model_filter = @search_params.delete(:model_filter)
|
22
23
|
@model = model
|
23
24
|
@client = client
|
24
25
|
end
|
@@ -91,9 +92,11 @@ module Aws
|
|
91
92
|
def _build_items_from_response(items, model)
|
92
93
|
ret = []
|
93
94
|
items.each do |item|
|
94
|
-
|
95
|
+
model_class = @model_filter ? @model_filter.call(item) : model
|
96
|
+
next unless model_class
|
97
|
+
record = model_class.new
|
95
98
|
data = record.instance_variable_get("@data")
|
96
|
-
|
99
|
+
model_class.attributes.attributes.each do |name, attr|
|
97
100
|
data.set_attribute(name, attr.extract(item))
|
98
101
|
end
|
99
102
|
data.clean!
|
@@ -122,9 +122,9 @@ module Aws
|
|
122
122
|
|
123
123
|
def populate_default_values
|
124
124
|
@model_attributes.attributes.each do |name, attribute|
|
125
|
-
unless attribute.default_value.nil?
|
125
|
+
unless (default_value = attribute.default_value).nil?
|
126
126
|
if @data[name].nil? && @data[name].nil?
|
127
|
-
@data[name] =
|
127
|
+
@data[name] = default_value
|
128
128
|
end
|
129
129
|
end
|
130
130
|
end
|
@@ -56,15 +56,24 @@ module Aws
|
|
56
56
|
# @param [Hash] opts options to pass on to the client call to
|
57
57
|
# +#create_table+. See the documentation above in the AWS SDK for Ruby
|
58
58
|
# V2.
|
59
|
-
# @option opts [Hash] :
|
60
|
-
#
|
59
|
+
# @option opts [Hash] :billing_mode Accepts values 'PAY_PER_REQUEST' or
|
60
|
+
# 'PROVISIONED'. If :provisioned_throughput option is specified, this
|
61
|
+
# option is not required, as 'PROVISIONED' is assumed. If
|
62
|
+
# :provisioned_throughput is not specified, this option is required
|
63
|
+
# and must be set to 'PAY_PER_REQUEST'.
|
64
|
+
# @option opts [Hash] :provisioned_throughput Unless :billing_mode is
|
65
|
+
# set to 'PAY_PER_REQUEST', this is a required argument, in which
|
66
|
+
# you must specify the +:read_capacity_units+ and
|
61
67
|
# +:write_capacity_units+ of your new table.
|
62
68
|
# @option opts [Hash] :global_secondary_index_throughput This argument is
|
63
|
-
# required if you define any global secondary indexes
|
69
|
+
# required if you define any global secondary indexes, unless
|
70
|
+
# :billing_mode is set to 'PAY_PER_REQUEST'. It should map your
|
64
71
|
# global secondary index names to their provisioned throughput, similar
|
65
72
|
# to how you define the provisioned throughput for the table in general.
|
66
73
|
def create!(opts)
|
67
74
|
gsit = opts.delete(:global_secondary_index_throughput)
|
75
|
+
_validate_billing(opts)
|
76
|
+
|
68
77
|
create_opts = opts.merge({
|
69
78
|
table_name: @model.table_name,
|
70
79
|
attribute_definitions: _attribute_definitions,
|
@@ -75,14 +84,19 @@ module Aws
|
|
75
84
|
_append_to_attribute_definitions(lsis, create_opts)
|
76
85
|
end
|
77
86
|
if gsis = @model.global_secondary_indexes_for_migration
|
78
|
-
unless gsit
|
87
|
+
unless gsit || opts[:billing_mode] == 'PAY_PER_REQUEST'
|
79
88
|
raise ArgumentError.new(
|
80
|
-
|
81
|
-
|
89
|
+
'If you define global secondary indexes, you must also define'\
|
90
|
+
' :global_secondary_index_throughput on table creation,'\
|
91
|
+
" unless :billing_mode is set to 'PAY_PER_REQUEST'."
|
82
92
|
)
|
83
93
|
end
|
84
|
-
|
85
|
-
|
94
|
+
gsis_opts = if opts[:billing_mode] == 'PAY_PER_REQUEST'
|
95
|
+
gsis
|
96
|
+
else
|
97
|
+
_add_throughput_to_gsis(gsis, gsit)
|
98
|
+
end
|
99
|
+
create_opts[:global_secondary_indexes] = gsis_opts
|
86
100
|
_append_to_attribute_definitions(gsis, create_opts)
|
87
101
|
end
|
88
102
|
@client.create_table(create_opts)
|
@@ -142,6 +156,33 @@ module Aws
|
|
142
156
|
end
|
143
157
|
end
|
144
158
|
|
159
|
+
def _validate_billing(opts)
|
160
|
+
valid_modes = %w[PAY_PER_REQUEST PROVISIONED]
|
161
|
+
if opts.key?(:billing_mode)
|
162
|
+
unless valid_modes.include?(opts[:billing_mode])
|
163
|
+
raise ArgumentError.new(
|
164
|
+
":billing_mode option must be one of #{valid_modes.join(', ')}"\
|
165
|
+
" current value is: #{opts[:billing_mode]}"
|
166
|
+
)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
if opts.key?(:provisioned_throughput)
|
170
|
+
if opts[:billing_mode] == 'PAY_PER_REQUEST'
|
171
|
+
raise ArgumentError.new(
|
172
|
+
'when :provisioned_throughput option is specified, :billing_mode'\
|
173
|
+
" must either be unspecified or have a value of 'PROVISIONED'"
|
174
|
+
)
|
175
|
+
end
|
176
|
+
else
|
177
|
+
if opts[:billing_mode] != 'PAY_PER_REQUEST'
|
178
|
+
raise ArgumentError.new(
|
179
|
+
'when :provisioned_throughput option is not specified,'\
|
180
|
+
" :billing_mode must be set to 'PAY_PER_REQUEST'"
|
181
|
+
)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
145
186
|
def _attribute_definitions
|
146
187
|
_keys.map do |type, attr|
|
147
188
|
{
|
@@ -173,7 +214,7 @@ module Aws
|
|
173
214
|
create_opts[:attribute_definitions] = attr_def
|
174
215
|
end
|
175
216
|
|
176
|
-
def
|
217
|
+
def _add_throughput_to_gsis(global_secondary_indexes, gsi_throughput)
|
177
218
|
missing_throughput = []
|
178
219
|
ret = global_secondary_indexes.map do |params|
|
179
220
|
name = params[:index_name]
|
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.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Amazon Web Services
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk-dynamodb
|
@@ -26,7 +26,8 @@ dependencies:
|
|
26
26
|
version: '1.18'
|
27
27
|
description: Provides an object mapping abstraction for Amazon DynamoDB.
|
28
28
|
email:
|
29
|
-
-
|
29
|
+
- mamuller@amazon.com
|
30
|
+
- alexwoo@amazon.com
|
30
31
|
executables: []
|
31
32
|
extensions: []
|
32
33
|
extra_rdoc_files: []
|
@@ -65,7 +66,7 @@ homepage: http://github.com/aws/aws-sdk-ruby-record
|
|
65
66
|
licenses:
|
66
67
|
- Apache 2.0
|
67
68
|
metadata: {}
|
68
|
-
post_install_message:
|
69
|
+
post_install_message:
|
69
70
|
rdoc_options: []
|
70
71
|
require_paths:
|
71
72
|
- lib
|
@@ -80,9 +81,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
80
81
|
- !ruby/object:Gem::Version
|
81
82
|
version: '0'
|
82
83
|
requirements: []
|
83
|
-
|
84
|
-
|
85
|
-
signing_key:
|
84
|
+
rubygems_version: 3.2.7
|
85
|
+
signing_key:
|
86
86
|
specification_version: 4
|
87
87
|
summary: AWS Record library for Amazon DynamoDB
|
88
88
|
test_files: []
|