toy-dynamo 0.1.3 → 0.1.4
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/lib/toy/dynamo/querying.rb +1 -1
- data/lib/toy/dynamo/schema.rb +68 -1
- data/lib/toy/dynamo/table.rb +37 -13
- data/lib/toy/dynamo/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a081dc7fc7b298bb5a17919dc56688f9aa504d4
|
4
|
+
data.tar.gz: 97616bc8ba2f9443c7915d9ea250ef5e50b0306c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c6d12a4a8cbd03bbb98f8d1ba283d28771e1896b73c9b5480ef750c3b17865c9bb75ae32f654863aa3ee023a4816b37b9f34aead2bf55f29f92802c5a8daacc9
|
7
|
+
data.tar.gz: 8a345618f030321fc03c0695a35467d6e79166ba7bc22e06eb1f71079462b5d4ec882c4ab018f84b871d1d9bee9651d6d25ab579cde485b643fe9d40fe7d5069
|
data/lib/toy/dynamo/querying.rb
CHANGED
@@ -14,7 +14,7 @@ module Toy
|
|
14
14
|
# Loop results in given batch size until limit is hit or no more results
|
15
15
|
# read_range("1", :range => { :varname.eq => "2"}, :batch => 10, :limit => 1000)
|
16
16
|
def read_range(hash_value, options={})
|
17
|
-
raise ArgumentError, "no range_key specified for this table" if dynamo_table.range_keys.blank?
|
17
|
+
raise ArgumentError, "no range_key specified for this table" if dynamo_table.range_keys.blank? && global_secondary_indexes.blank?
|
18
18
|
aggregated_results = []
|
19
19
|
|
20
20
|
batch_size = options.delete(:batch) || DEFAULT_BATCH_SIZE
|
data/lib/toy/dynamo/schema.rb
CHANGED
@@ -50,6 +50,7 @@ module Toy
|
|
50
50
|
:attribute_definitions => attribute_definitions
|
51
51
|
}
|
52
52
|
schema[:local_secondary_indexes] = local_secondary_indexes unless local_secondary_indexes.blank?
|
53
|
+
schema[:global_secondary_indexes] = global_secondary_indexes unless global_secondary_indexes.blank?
|
53
54
|
schema
|
54
55
|
end
|
55
56
|
|
@@ -94,6 +95,12 @@ module Toy
|
|
94
95
|
keys << lsi[:key_schema].select{|h| h[:key_type] == "RANGE"}.first[:attribute_name]
|
95
96
|
end
|
96
97
|
|
98
|
+
global_secondary_indexes.each do |lsi|
|
99
|
+
lsi[:key_schema].each do |a|
|
100
|
+
keys << a[:attribute_name]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
97
104
|
definitions = keys.uniq.collect do |k|
|
98
105
|
attr = self.attributes[k.to_s]
|
99
106
|
{
|
@@ -197,6 +204,66 @@ module Toy
|
|
197
204
|
end
|
198
205
|
end
|
199
206
|
|
207
|
+
def global_secondary_indexes
|
208
|
+
@global_secondary_indexes ||= []
|
209
|
+
end
|
210
|
+
|
211
|
+
# { hash_key: :hash_key_here, range_key: :optional_range_key_here }
|
212
|
+
# :name
|
213
|
+
# :projection
|
214
|
+
# :read_provision
|
215
|
+
# :write_provision
|
216
|
+
def global_secondary_index(index_name, options={})
|
217
|
+
options[:projection] ||= :keys_only
|
218
|
+
global_secondary_index_hash = {
|
219
|
+
:projection => {},
|
220
|
+
:provisioned_throughput => {
|
221
|
+
:read_capacity_units => options[:read_provision] || read_provision,
|
222
|
+
:write_capacity_units => options[:write_provision] || write_provision
|
223
|
+
}
|
224
|
+
}
|
225
|
+
if options[:projection].is_a?(Array) && options[:projection].size > 0
|
226
|
+
options[:projection].each do |non_key_attr|
|
227
|
+
attr = self.attributes[non_key_attr.to_s]
|
228
|
+
raise(ArgumentError, "Could not find attribute definition for projection on #{non_key_attr}") unless attr
|
229
|
+
(global_secondary_index_hash[:projection][:non_key_attributes] ||= []) << attr.name
|
230
|
+
end
|
231
|
+
global_secondary_index_hash[:projection][:projection_type] = PROJECTION_TYPE[:include]
|
232
|
+
else
|
233
|
+
raise(ArgumentError, 'projection must be :all, :keys_only, Array (or attrs)') unless options[:projection] == :keys_only || options[:projection] == :all
|
234
|
+
global_secondary_index_hash[:projection][:projection_type] = PROJECTION_TYPE[options[:projection]]
|
235
|
+
end
|
236
|
+
|
237
|
+
if !options.has_key?(:hash_key) || self.attributes[options[:hash_key].to_s].blank?
|
238
|
+
raise(ArgumentError, "Could not find attribute definition for global secondary index on hash_key specified")
|
239
|
+
end
|
240
|
+
hash_key_attr = self.attributes[options[:hash_key].to_s]
|
241
|
+
|
242
|
+
if options.has_key?(:range_key) && self.attributes[options[:range_key].to_s].blank?
|
243
|
+
raise(ArgumentError, "Could not find attribute definition for global secondary index on range_key specified")
|
244
|
+
end
|
245
|
+
range_key_attr = nil
|
246
|
+
range_key_attr = self.attributes[options[:range_key].to_s] if options.has_key?(:range_key)
|
247
|
+
|
248
|
+
## Force naming of index_name for lookup later
|
249
|
+
#global_secondary_index_hash[:index_name] = (index_name.to_s || "#{hash_key_attr.name}#{"_#{range_key_attr.name}" if range_key_attr}_gsi_index".camelcase)
|
250
|
+
global_secondary_index_hash[:index_name] = index_name.to_s
|
251
|
+
|
252
|
+
global_secondary_index_hash[:key_schema] = [
|
253
|
+
{
|
254
|
+
:attribute_name => hash_key_attr.name,
|
255
|
+
:key_type => KEY_TYPE[:hash]
|
256
|
+
}
|
257
|
+
]
|
258
|
+
global_secondary_index_hash[:key_schema] << {
|
259
|
+
:attribute_name => range_key_attr.name,
|
260
|
+
:key_type => KEY_TYPE[:range]
|
261
|
+
} if range_key_attr
|
262
|
+
|
263
|
+
return false if (@global_secondary_indexes ||= []).select {|i| i[:index_name] == global_secondary_index_hash[:index_name] }.present? # Do not add if we already have a range key set for this attr
|
264
|
+
(@global_secondary_indexes ||= []) << global_secondary_index_hash
|
265
|
+
end
|
266
|
+
|
200
267
|
def local_secondary_indexes
|
201
268
|
@local_secondary_indexes ||= []
|
202
269
|
end
|
@@ -226,7 +293,7 @@ module Toy
|
|
226
293
|
|
227
294
|
range_attr = self.attributes[range_key_attr.to_s]
|
228
295
|
raise(ArgumentError, "Could not find attribute definition for local secondary index on #{range_key_attr}") unless range_attr
|
229
|
-
local_secondary_index_hash[:index_name] = (options[:name] || "#{range_attr.name}_index".camelcase)
|
296
|
+
local_secondary_index_hash[:index_name] = (options[:name] || options[:index_name] || "#{range_attr.name}_index".camelcase)
|
230
297
|
|
231
298
|
hash_key_attr = self.attributes[hash_key[:attribute_name].to_s]
|
232
299
|
raise(ArgumentError, "Could not find attribute definition for hash_key") unless hash_key_attr
|
data/lib/toy/dynamo/table.rb
CHANGED
@@ -74,14 +74,15 @@ module Toy
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
if @schema_loaded_from_dynamo[:table][:local_secondary_indexes]
|
78
|
-
@schema_loaded_from_dynamo[:table][:local_secondary_indexes].each do |key|
|
79
|
-
|
80
|
-
|
81
|
-
|
77
|
+
if @schema_loaded_from_dynamo[:table][:local_secondary_indexes] || @schema_loaded_from_dynamo[:table][:global_secondary_indexes]
|
78
|
+
((@schema_loaded_from_dynamo[:table][:local_secondary_indexes] || []) + (@schema_loaded_from_dynamo[:table][:global_secondary_indexes] || [])).each do |key|
|
79
|
+
si_range_key = key[:key_schema].find{|h| h[:key_type] == "RANGE" }
|
80
|
+
next if si_range_key.nil?
|
81
|
+
si_range_attribute = @table_schema[:attribute_definitions].find{|h| h[:attribute_name] == si_range_key[:attribute_name]}
|
82
|
+
next if si_range_attribute.nil?
|
82
83
|
(@range_keys ||= []) << {
|
83
|
-
:attribute_name =>
|
84
|
-
:attribute_type =>
|
84
|
+
:attribute_name => si_range_key[:attribute_name],
|
85
|
+
:attribute_type => si_range_attribute[:attribute_type],
|
85
86
|
:index_name => key[:index_name]
|
86
87
|
}
|
87
88
|
end
|
@@ -96,8 +97,7 @@ module Toy
|
|
96
97
|
{ hash_key => { hash_key_type => value } }
|
97
98
|
end
|
98
99
|
|
99
|
-
def hash_key_condition_param(value)
|
100
|
-
hash_key = @table_schema[:key_schema].find{|h| h[:key_type] == "HASH"}[:attribute_name]
|
100
|
+
def hash_key_condition_param(hash_key, value)
|
101
101
|
hash_key_type = @table_schema[:attribute_definitions].find{|h| h[:attribute_name] == hash_key}[:attribute_type]
|
102
102
|
{
|
103
103
|
hash_key => {
|
@@ -142,7 +142,17 @@ module Toy
|
|
142
142
|
#options[:exclusive_start_key]
|
143
143
|
|
144
144
|
key_conditions = {}
|
145
|
-
|
145
|
+
gsi = nil
|
146
|
+
if options[:global_secondary_index]
|
147
|
+
# TODO
|
148
|
+
gsi = @table_schema[:global_secondary_indexes].select{ |gsi| gsi[:index_name].to_s == options[:global_secondary_index].to_s}.first
|
149
|
+
raise ArgumentError, "Could not find Global Secondary Index '#{options[:global_secondary_index]}'" unless gsi
|
150
|
+
gsi_hash_key = gsi[:key_schema].find{|h| h[:key_type] == "HASH"}[:attribute_name]
|
151
|
+
key_conditions.merge!(hash_key_condition_param(gsi_hash_key, hash_key_value))
|
152
|
+
else
|
153
|
+
hash_key = @table_schema[:key_schema].find{|h| h[:key_type] == "HASH"}[:attribute_name]
|
154
|
+
key_conditions.merge!(hash_key_condition_param(hash_key, hash_key_value))
|
155
|
+
end
|
146
156
|
|
147
157
|
query_request = {
|
148
158
|
:table_name => options[:table_name] || self.table_name,
|
@@ -153,14 +163,24 @@ module Toy
|
|
153
163
|
}
|
154
164
|
|
155
165
|
if options[:range]
|
156
|
-
raise ArgumentError, "Expected a 1 element Hash for :range (ex {:age.gt => 13})" unless options[:range].is_a?(Hash) && options[:range].keys.size == 1
|
166
|
+
raise ArgumentError, "Expected a 1 element Hash for :range (ex {:age.gt => 13})" unless options[:range].is_a?(Hash) && options[:range].keys.size == 1 && options[:range].keys.first.is_a?(String)
|
157
167
|
range_key_name, comparison_operator = options[:range].keys.first.split(".")
|
158
168
|
raise ArgumentError, "Comparison operator must be one of (#{(COMPARISON_OPERATOR.keys - COMPARISON_OPERATOR_SCAN_ONLY).join(", ")})" unless COMPARISON_OPERATOR.keys.include?(comparison_operator.to_sym)
|
159
|
-
range_key =
|
169
|
+
range_key = nil
|
170
|
+
#[{:attribute_name=>"health_check_guid", :attribute_type=>"S", :primary_range_key=>true}]
|
171
|
+
#raise @range_keys.inspect
|
172
|
+
#if options[:global_secondary_index]
|
173
|
+
#raise @table_schema.inspect
|
174
|
+
#hash_key_type = @table_schema[:attribute_definitions].find{|h| h[:attribute_name] == hash_key}[:attribute_type]
|
175
|
+
#raise gsi[:key_schema].inspect
|
176
|
+
##range_key = gsi.find{|k| k[:attribute_name] == range_key_name}
|
177
|
+
#else
|
178
|
+
range_key = @range_keys.find{|k| k[:attribute_name] == range_key_name}
|
179
|
+
#end
|
160
180
|
raise ArgumentError, ":range key must be a valid Range attribute" unless range_key
|
161
181
|
raise ArgumentError, ":range key must be a Range if using the operator BETWEEN" if comparison_operator == "between" && !options[:range].values.first.is_a?(Range)
|
162
182
|
|
163
|
-
if range_key.has_key?(:index_name) # Local Secondary Index
|
183
|
+
if range_key.has_key?(:index_name) # Local/Global Secondary Index
|
164
184
|
#options[:select] = :projected unless options[:select].present?
|
165
185
|
query_request.merge!(:index_name => range_key[:index_name])
|
166
186
|
end
|
@@ -183,6 +203,10 @@ module Toy
|
|
183
203
|
})
|
184
204
|
end
|
185
205
|
|
206
|
+
if options[:global_secondary_index] # Override index_name if using GSI
|
207
|
+
query_request.merge!(:index_name => gsi[:index_name])
|
208
|
+
end
|
209
|
+
|
186
210
|
# Default if not already set
|
187
211
|
options[:select] ||= :all # :all, :projected, :count, []
|
188
212
|
if options[:select].is_a?(Array)
|
data/lib/toy/dynamo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: toy-dynamo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cary Dunn
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-12-
|
11
|
+
date: 2013-12-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|