dynamoid 3.1.0 → 3.2.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 +5 -5
- data/.rubocop.yml +18 -0
- data/.travis.yml +5 -3
- data/CHANGELOG.md +15 -0
- data/README.md +113 -63
- data/Vagrantfile +2 -2
- data/docker-compose.yml +1 -1
- data/gemfiles/rails_4_2.gemfile +1 -1
- data/gemfiles/rails_5_0.gemfile +1 -1
- data/gemfiles/rails_5_1.gemfile +1 -1
- data/gemfiles/rails_5_2.gemfile +1 -1
- data/lib/dynamoid/adapter.rb +1 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3.rb +26 -395
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/create_table.rb +234 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/item_updater.rb +89 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/backoff.rb +24 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/limit.rb +57 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/middleware/start_key.rb +28 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/query.rb +123 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/scan.rb +85 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/table.rb +52 -0
- data/lib/dynamoid/adapter_plugin/aws_sdk_v3/until_past_table_status.rb +60 -0
- data/lib/dynamoid/associations/has_and_belongs_to_many.rb +1 -0
- data/lib/dynamoid/associations/has_many.rb +1 -0
- data/lib/dynamoid/associations/has_one.rb +1 -0
- data/lib/dynamoid/associations/single_association.rb +1 -0
- data/lib/dynamoid/criteria.rb +4 -4
- data/lib/dynamoid/criteria/chain.rb +86 -79
- data/lib/dynamoid/criteria/ignored_conditions_detector.rb +41 -0
- data/lib/dynamoid/criteria/key_fields_detector.rb +61 -0
- data/lib/dynamoid/criteria/nonexistent_fields_detector.rb +41 -0
- data/lib/dynamoid/criteria/overwritten_conditions_detector.rb +40 -0
- data/lib/dynamoid/document.rb +18 -13
- data/lib/dynamoid/dumping.rb +52 -40
- data/lib/dynamoid/fields.rb +4 -3
- data/lib/dynamoid/finders.rb +3 -3
- data/lib/dynamoid/persistence.rb +5 -6
- data/lib/dynamoid/primary_key_type_mapping.rb +1 -1
- data/lib/dynamoid/tasks.rb +1 -0
- data/lib/dynamoid/tasks/database.rake +2 -2
- data/lib/dynamoid/type_casting.rb +37 -19
- data/lib/dynamoid/undumping.rb +53 -42
- data/lib/dynamoid/validations.rb +2 -0
- data/lib/dynamoid/version.rb +1 -1
- metadata +17 -5
- data/lib/dynamoid/adapter_plugin/query.rb +0 -144
- data/lib/dynamoid/adapter_plugin/scan.rb +0 -107
@@ -0,0 +1,234 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'until_past_table_status'
|
4
|
+
|
5
|
+
module Dynamoid
|
6
|
+
module AdapterPlugin
|
7
|
+
class AwsSdkV3
|
8
|
+
class CreateTable
|
9
|
+
attr_reader :client, :table_name, :key, :options
|
10
|
+
|
11
|
+
def initialize(client, table_name, key, options)
|
12
|
+
@client = client
|
13
|
+
@table_name = table_name
|
14
|
+
@key = key
|
15
|
+
@options = options
|
16
|
+
end
|
17
|
+
|
18
|
+
def call
|
19
|
+
read_capacity = options[:read_capacity] || Dynamoid::Config.read_capacity
|
20
|
+
write_capacity = options[:write_capacity] || Dynamoid::Config.write_capacity
|
21
|
+
|
22
|
+
secondary_indexes = options.slice(
|
23
|
+
:local_secondary_indexes,
|
24
|
+
:global_secondary_indexes
|
25
|
+
)
|
26
|
+
ls_indexes = options[:local_secondary_indexes]
|
27
|
+
gs_indexes = options[:global_secondary_indexes]
|
28
|
+
|
29
|
+
key_schema = {
|
30
|
+
hash_key_schema: { key => (options[:hash_key_type] || :string) },
|
31
|
+
range_key_schema: options[:range_key]
|
32
|
+
}
|
33
|
+
attribute_definitions = build_all_attribute_definitions(
|
34
|
+
key_schema,
|
35
|
+
secondary_indexes
|
36
|
+
)
|
37
|
+
key_schema = aws_key_schema(
|
38
|
+
key_schema[:hash_key_schema],
|
39
|
+
key_schema[:range_key_schema]
|
40
|
+
)
|
41
|
+
|
42
|
+
client_opts = {
|
43
|
+
table_name: table_name,
|
44
|
+
provisioned_throughput: {
|
45
|
+
read_capacity_units: read_capacity,
|
46
|
+
write_capacity_units: write_capacity
|
47
|
+
},
|
48
|
+
key_schema: key_schema,
|
49
|
+
attribute_definitions: attribute_definitions
|
50
|
+
}
|
51
|
+
|
52
|
+
if ls_indexes.present?
|
53
|
+
client_opts[:local_secondary_indexes] = ls_indexes.map do |index|
|
54
|
+
index_to_aws_hash(index)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if gs_indexes.present?
|
59
|
+
client_opts[:global_secondary_indexes] = gs_indexes.map do |index|
|
60
|
+
index_to_aws_hash(index)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
resp = client.create_table(client_opts)
|
64
|
+
options[:sync] = true if !options.key?(:sync) && ls_indexes.present? || gs_indexes.present?
|
65
|
+
UntilPastTableStatus.new(table_name, :creating).call if options[:sync] &&
|
66
|
+
(status = PARSE_TABLE_STATUS.call(resp, :table_description)) &&
|
67
|
+
status == TABLE_STATUSES[:creating]
|
68
|
+
# Response to original create_table, which, if options[:sync]
|
69
|
+
# may have an outdated table_description.table_status of "CREATING"
|
70
|
+
resp
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# Builds aws attributes definitions based off of primary hash/range and
|
76
|
+
# secondary indexes
|
77
|
+
#
|
78
|
+
# @param key_data
|
79
|
+
# @option key_data [Hash] hash_key_schema - eg: {:id => :string}
|
80
|
+
# @option key_data [Hash] range_key_schema - eg: {:created_at => :number}
|
81
|
+
# @param [Hash] secondary_indexes
|
82
|
+
# @option secondary_indexes [Array<Dynamoid::Indexes::Index>] :local_secondary_indexes
|
83
|
+
# @option secondary_indexes [Array<Dynamoid::Indexes::Index>] :global_secondary_indexes
|
84
|
+
def build_all_attribute_definitions(key_schema, secondary_indexes = {})
|
85
|
+
ls_indexes = secondary_indexes[:local_secondary_indexes]
|
86
|
+
gs_indexes = secondary_indexes[:global_secondary_indexes]
|
87
|
+
|
88
|
+
attribute_definitions = []
|
89
|
+
|
90
|
+
attribute_definitions << build_attribute_definitions(
|
91
|
+
key_schema[:hash_key_schema],
|
92
|
+
key_schema[:range_key_schema]
|
93
|
+
)
|
94
|
+
|
95
|
+
if ls_indexes.present?
|
96
|
+
ls_indexes.map do |index|
|
97
|
+
attribute_definitions << build_attribute_definitions(
|
98
|
+
index.hash_key_schema,
|
99
|
+
index.range_key_schema
|
100
|
+
)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if gs_indexes.present?
|
105
|
+
gs_indexes.map do |index|
|
106
|
+
attribute_definitions << build_attribute_definitions(
|
107
|
+
index.hash_key_schema,
|
108
|
+
index.range_key_schema
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
attribute_definitions.flatten!
|
114
|
+
# uniq these definitions because range keys might be common between
|
115
|
+
# primary and secondary indexes
|
116
|
+
attribute_definitions.uniq!
|
117
|
+
attribute_definitions
|
118
|
+
end
|
119
|
+
|
120
|
+
# Builds an attribute definitions based on hash key and range key
|
121
|
+
# @params [Hash] hash_key_schema - eg: {:id => :string}
|
122
|
+
# @params [Hash] range_key_schema - eg: {:created_at => :datetime}
|
123
|
+
# @return [Array]
|
124
|
+
def build_attribute_definitions(hash_key_schema, range_key_schema = nil)
|
125
|
+
attrs = []
|
126
|
+
|
127
|
+
attrs << attribute_definition_element(
|
128
|
+
hash_key_schema.keys.first,
|
129
|
+
hash_key_schema.values.first
|
130
|
+
)
|
131
|
+
|
132
|
+
if range_key_schema.present?
|
133
|
+
attrs << attribute_definition_element(
|
134
|
+
range_key_schema.keys.first,
|
135
|
+
range_key_schema.values.first
|
136
|
+
)
|
137
|
+
end
|
138
|
+
|
139
|
+
attrs
|
140
|
+
end
|
141
|
+
|
142
|
+
# Builds an aws attribute definition based on name and dynamoid type
|
143
|
+
# @params [Symbol] name - eg: :id
|
144
|
+
# @params [Symbol] dynamoid_type - eg: :string
|
145
|
+
# @return [Hash]
|
146
|
+
def attribute_definition_element(name, dynamoid_type)
|
147
|
+
aws_type = api_type(dynamoid_type)
|
148
|
+
|
149
|
+
{
|
150
|
+
attribute_name: name.to_s,
|
151
|
+
attribute_type: aws_type
|
152
|
+
}
|
153
|
+
end
|
154
|
+
|
155
|
+
# Converts from symbol to the API string for the given data type
|
156
|
+
# E.g. :number -> 'N'
|
157
|
+
def api_type(type)
|
158
|
+
case type
|
159
|
+
when :string then STRING_TYPE
|
160
|
+
when :number then NUM_TYPE
|
161
|
+
when :binary then BINARY_TYPE
|
162
|
+
else raise "Unknown type: #{type}"
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
# Converts a Dynamoid::Indexes::Index to an AWS API-compatible hash.
|
167
|
+
# This resulting hash is of the form:
|
168
|
+
#
|
169
|
+
# {
|
170
|
+
# index_name: String
|
171
|
+
# keys: {
|
172
|
+
# hash_key: aws_key_schema (hash)
|
173
|
+
# range_key: aws_key_schema (hash)
|
174
|
+
# }
|
175
|
+
# projection: {
|
176
|
+
# projection_type: (ALL, KEYS_ONLY, INCLUDE) String
|
177
|
+
# non_key_attributes: (optional) Array
|
178
|
+
# }
|
179
|
+
# provisioned_throughput: {
|
180
|
+
# read_capacity_units: Integer
|
181
|
+
# write_capacity_units: Integer
|
182
|
+
# }
|
183
|
+
# }
|
184
|
+
#
|
185
|
+
# @param [Dynamoid::Indexes::Index] index the index.
|
186
|
+
# @return [Hash] hash representing an AWS Index definition.
|
187
|
+
def index_to_aws_hash(index)
|
188
|
+
key_schema = aws_key_schema(index.hash_key_schema, index.range_key_schema)
|
189
|
+
|
190
|
+
hash = {
|
191
|
+
index_name: index.name,
|
192
|
+
key_schema: key_schema,
|
193
|
+
projection: {
|
194
|
+
projection_type: index.projection_type.to_s.upcase
|
195
|
+
}
|
196
|
+
}
|
197
|
+
|
198
|
+
# If the projection type is include, specify the non key attributes
|
199
|
+
if index.projection_type == :include
|
200
|
+
hash[:projection][:non_key_attributes] = index.projected_attributes
|
201
|
+
end
|
202
|
+
|
203
|
+
# Only global secondary indexes have a separate throughput.
|
204
|
+
if index.type == :global_secondary
|
205
|
+
hash[:provisioned_throughput] = {
|
206
|
+
read_capacity_units: index.read_capacity,
|
207
|
+
write_capacity_units: index.write_capacity
|
208
|
+
}
|
209
|
+
end
|
210
|
+
hash
|
211
|
+
end
|
212
|
+
|
213
|
+
# Converts hash_key_schema and range_key_schema to aws_key_schema
|
214
|
+
# @param [Hash] hash_key_schema eg: {:id => :string}
|
215
|
+
# @param [Hash] range_key_schema eg: {:created_at => :number}
|
216
|
+
# @return [Array]
|
217
|
+
def aws_key_schema(hash_key_schema, range_key_schema)
|
218
|
+
schema = [{
|
219
|
+
attribute_name: hash_key_schema.keys.first.to_s,
|
220
|
+
key_type: HASH_KEY
|
221
|
+
}]
|
222
|
+
|
223
|
+
if range_key_schema.present?
|
224
|
+
schema << {
|
225
|
+
attribute_name: range_key_schema.keys.first.to_s,
|
226
|
+
key_type: RANGE_KEY
|
227
|
+
}
|
228
|
+
end
|
229
|
+
schema
|
230
|
+
end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dynamoid
|
4
|
+
module AdapterPlugin
|
5
|
+
class AwsSdkV3
|
6
|
+
# Mimics behavior of the yielded object on DynamoDB's update_item API (high level).
|
7
|
+
class ItemUpdater
|
8
|
+
attr_reader :table, :key, :range_key
|
9
|
+
|
10
|
+
def initialize(table, key, range_key = nil)
|
11
|
+
@table = table
|
12
|
+
@key = key
|
13
|
+
@range_key = range_key
|
14
|
+
@additions = {}
|
15
|
+
@deletions = {}
|
16
|
+
@updates = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Adds the given values to the values already stored in the corresponding columns.
|
21
|
+
# The column must contain a Set or a number.
|
22
|
+
#
|
23
|
+
# @param [Hash] vals keys of the hash are the columns to update, vals are the values to
|
24
|
+
# add. values must be a Set, Array, or Numeric
|
25
|
+
#
|
26
|
+
def add(values)
|
27
|
+
@additions.merge!(sanitize_attributes(values))
|
28
|
+
end
|
29
|
+
|
30
|
+
#
|
31
|
+
# Removes values from the sets of the given columns
|
32
|
+
#
|
33
|
+
# @param [Hash] values keys of the hash are the columns, values are Arrays/Sets of items
|
34
|
+
# to remove
|
35
|
+
#
|
36
|
+
def delete(values)
|
37
|
+
@deletions.merge!(sanitize_attributes(values))
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Replaces the values of one or more attributes
|
42
|
+
#
|
43
|
+
def set(values)
|
44
|
+
@updates.merge!(sanitize_attributes(values))
|
45
|
+
end
|
46
|
+
|
47
|
+
#
|
48
|
+
# Returns an AttributeUpdates hash suitable for passing to the V2 Client API
|
49
|
+
#
|
50
|
+
def to_h
|
51
|
+
ret = {}
|
52
|
+
|
53
|
+
@additions.each do |k, v|
|
54
|
+
ret[k.to_s] = {
|
55
|
+
action: ADD,
|
56
|
+
value: v
|
57
|
+
}
|
58
|
+
end
|
59
|
+
@deletions.each do |k, v|
|
60
|
+
ret[k.to_s] = {
|
61
|
+
action: DELETE,
|
62
|
+
value: v
|
63
|
+
}
|
64
|
+
end
|
65
|
+
@updates.each do |k, v|
|
66
|
+
ret[k.to_s] = {
|
67
|
+
action: PUT,
|
68
|
+
value: v
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
ret
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def sanitize_attributes(attributes)
|
78
|
+
attributes.transform_values do |v|
|
79
|
+
v.is_a?(Hash) ? v.stringify_keys : v
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
ADD = 'ADD'
|
84
|
+
DELETE = 'DELETE'
|
85
|
+
PUT = 'PUT'
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dynamoid
|
4
|
+
module AdapterPlugin
|
5
|
+
class AwsSdkV3
|
6
|
+
module Middleware
|
7
|
+
class Backoff
|
8
|
+
def initialize(next_chain)
|
9
|
+
@next_chain = next_chain
|
10
|
+
@backoff = Dynamoid.config.backoff ? Dynamoid.config.build_backoff : nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(request)
|
14
|
+
response = @next_chain.call(request)
|
15
|
+
@backoff.call if @backoff
|
16
|
+
|
17
|
+
return response
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dynamoid
|
4
|
+
module AdapterPlugin
|
5
|
+
class AwsSdkV3
|
6
|
+
module Middleware
|
7
|
+
class Limit
|
8
|
+
def initialize(next_chain, record_limit: nil, scan_limit: nil)
|
9
|
+
@next_chain = next_chain
|
10
|
+
|
11
|
+
@record_limit = record_limit
|
12
|
+
@scan_limit = scan_limit
|
13
|
+
|
14
|
+
@record_count = 0
|
15
|
+
@scan_count = 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(request)
|
19
|
+
# Adjust the limit down if the remaining record and/or scan limit are
|
20
|
+
# lower to obey limits. We can assume the difference won't be
|
21
|
+
# negative due to break statements below but choose smaller limit
|
22
|
+
# which is why we have 2 separate if statements.
|
23
|
+
# NOTE: Adjusting based on record_limit can cause many HTTP requests
|
24
|
+
# being made. We may want to change this behavior, but it affects
|
25
|
+
# filtering on data with potentially large gaps.
|
26
|
+
# Example:
|
27
|
+
# User.where('created_at.gte' => 1.day.ago).record_limit(1000)
|
28
|
+
# Records 1-999 User's that fit criteria
|
29
|
+
# Records 1000-2000 Users's that do not fit criteria
|
30
|
+
# Record 2001 fits criteria
|
31
|
+
# The underlying implementation will have 1 page for records 1-999
|
32
|
+
# then will request with limit 1 for records 1000-2000 (making 1000
|
33
|
+
# requests of limit 1) until hit record 2001.
|
34
|
+
if request[:limit] && @record_limit && @record_limit - @record_count < request[:limit]
|
35
|
+
request[:limit] = @record_limit - @record_count
|
36
|
+
end
|
37
|
+
if request[:limit] && @scan_limit && @scan_limit - @scan_count < request[:limit]
|
38
|
+
request[:limit] = @scan_limit - @scan_count
|
39
|
+
end
|
40
|
+
|
41
|
+
response = @next_chain.call(request)
|
42
|
+
|
43
|
+
@record_count += response.count
|
44
|
+
throw :stop_pagination if @record_limit && @record_count >= @record_limit
|
45
|
+
|
46
|
+
@scan_count += response.scanned_count
|
47
|
+
throw :stop_pagination if @scan_limit && @scan_count >= @scan_limit
|
48
|
+
|
49
|
+
return response
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Dynamoid
|
4
|
+
module AdapterPlugin
|
5
|
+
class AwsSdkV3
|
6
|
+
module Middleware
|
7
|
+
class StartKey
|
8
|
+
def initialize(next_chain)
|
9
|
+
@next_chain = next_chain
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(request)
|
13
|
+
response = @next_chain.call(request)
|
14
|
+
|
15
|
+
if response.last_evaluated_key
|
16
|
+
request[:exclusive_start_key] = response.last_evaluated_key
|
17
|
+
else
|
18
|
+
throw :stop_pagination
|
19
|
+
end
|
20
|
+
|
21
|
+
return response
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'middleware/backoff'
|
4
|
+
require_relative 'middleware/limit'
|
5
|
+
require_relative 'middleware/start_key'
|
6
|
+
|
7
|
+
module Dynamoid
|
8
|
+
module AdapterPlugin
|
9
|
+
class AwsSdkV3
|
10
|
+
class Query
|
11
|
+
OPTIONS_KEYS = %i[
|
12
|
+
limit hash_key hash_value range_key consistent_read scan_index_forward
|
13
|
+
select index_name batch_size exclusive_start_key record_limit scan_limit
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
attr_reader :client, :table, :options, :conditions
|
17
|
+
|
18
|
+
def initialize(client, table, opts = {})
|
19
|
+
@client = client
|
20
|
+
@table = table
|
21
|
+
|
22
|
+
opts = opts.symbolize_keys
|
23
|
+
@options = opts.slice(*OPTIONS_KEYS)
|
24
|
+
@conditions = opts.except(*OPTIONS_KEYS)
|
25
|
+
end
|
26
|
+
|
27
|
+
def call
|
28
|
+
request = build_request
|
29
|
+
|
30
|
+
Enumerator.new do |yielder|
|
31
|
+
api_call = -> (request) do
|
32
|
+
client.query(request).tap do |response|
|
33
|
+
yielder << response
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
middlewares = Middleware::Backoff.new(
|
38
|
+
Middleware::StartKey.new(
|
39
|
+
Middleware::Limit.new(api_call, record_limit: record_limit, scan_limit: scan_limit)
|
40
|
+
)
|
41
|
+
)
|
42
|
+
|
43
|
+
catch :stop_pagination do
|
44
|
+
loop do
|
45
|
+
middlewares.call(request)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def build_request
|
54
|
+
request = options.slice(
|
55
|
+
:consistent_read,
|
56
|
+
:scan_index_forward,
|
57
|
+
:select,
|
58
|
+
:index_name,
|
59
|
+
:exclusive_start_key
|
60
|
+
).compact
|
61
|
+
|
62
|
+
# Deal with various limits and batching
|
63
|
+
batch_size = options[:batch_size]
|
64
|
+
limit = [record_limit, scan_limit, batch_size].compact.min
|
65
|
+
|
66
|
+
request[:limit] = limit if limit
|
67
|
+
request[:table_name] = table.name
|
68
|
+
request[:key_conditions] = key_conditions
|
69
|
+
request[:query_filter] = query_filter
|
70
|
+
|
71
|
+
request
|
72
|
+
end
|
73
|
+
|
74
|
+
def record_limit
|
75
|
+
options[:record_limit]
|
76
|
+
end
|
77
|
+
|
78
|
+
def scan_limit
|
79
|
+
options[:scan_limit]
|
80
|
+
end
|
81
|
+
|
82
|
+
def hash_key_name
|
83
|
+
(options[:hash_key] || table.hash_key)
|
84
|
+
end
|
85
|
+
|
86
|
+
def range_key_name
|
87
|
+
(options[:range_key] || table.range_key)
|
88
|
+
end
|
89
|
+
|
90
|
+
def key_conditions
|
91
|
+
result = {
|
92
|
+
hash_key_name => {
|
93
|
+
comparison_operator: AwsSdkV3::EQ,
|
94
|
+
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::EQ, options[:hash_value].freeze)
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
conditions.slice(*AwsSdkV3::RANGE_MAP.keys).each do |k, _v|
|
99
|
+
op = AwsSdkV3::RANGE_MAP[k]
|
100
|
+
|
101
|
+
result[range_key_name] = {
|
102
|
+
comparison_operator: op,
|
103
|
+
attribute_value_list: AwsSdkV3.attribute_value_list(op, conditions[k].freeze)
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
result
|
108
|
+
end
|
109
|
+
|
110
|
+
def query_filter
|
111
|
+
conditions.except(*AwsSdkV3::RANGE_MAP.keys).reduce({}) do |result, (attr, cond)|
|
112
|
+
condition = {
|
113
|
+
comparison_operator: AwsSdkV3::FIELD_MAP[cond.keys[0]],
|
114
|
+
attribute_value_list: AwsSdkV3.attribute_value_list(AwsSdkV3::FIELD_MAP[cond.keys[0]], cond.values[0].freeze)
|
115
|
+
}
|
116
|
+
result[attr] = condition
|
117
|
+
result
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|