toy-dynamo 0.1.3 → 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
|