dynamoid-edge 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/dynamoid-edge.gemspec +2 -1
- data/lib/dynamoid/indexes.rb +273 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 80ef1eaf479540803590814d5cf4d531faa12cf2
|
4
|
+
data.tar.gz: 901734ae300344fd6294f83818781216ad3f3425
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fde56e03afd236911cd55022d3581dc9974248cf2b4b5656bef9fb9de32c631fd9962bbad637da971b52c54531aec3f028e7c34541a29ff7df862b4dad9ae51
|
7
|
+
data.tar.gz: 7bfe7c2c91508f757b2018a6d9459cc5f306a0ef2d84eadfd004c534ce5c68cd763cbec842cce3055117c60deb9174604cff845ec40ccf9c46afec07fec6fde1
|
data/dynamoid-edge.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "dynamoid-edge"
|
5
|
-
s.version = "1.1.
|
5
|
+
s.version = "1.1.1"
|
6
6
|
|
7
7
|
# Keep in sync with README
|
8
8
|
s.authors = [
|
@@ -51,6 +51,7 @@ Gem::Specification.new do |s|
|
|
51
51
|
lib/dynamoid/fields.rb
|
52
52
|
lib/dynamoid/finders.rb
|
53
53
|
lib/dynamoid/identity_map.rb
|
54
|
+
lib/dynamoid/indexes.rb
|
54
55
|
lib/dynamoid/middleware/identity_map.rb
|
55
56
|
lib/dynamoid/persistence.rb
|
56
57
|
lib/dynamoid/validations.rb
|
@@ -0,0 +1,273 @@
|
|
1
|
+
module Dynamoid
|
2
|
+
module Indexes
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :local_secondary_indexes
|
7
|
+
class_attribute :global_secondary_indexes
|
8
|
+
self.local_secondary_indexes = {}
|
9
|
+
self.global_secondary_indexes = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# Defines a Global Secondary index on a table. Keys can be specified as
|
14
|
+
# hash-only, or hash & range.
|
15
|
+
#
|
16
|
+
# @param [Hash] options options to pass for this table
|
17
|
+
# @option options [Symbol] :name the name for the index; this still gets
|
18
|
+
# namespaced. If not specified, will use a default name.
|
19
|
+
# @option options [Symbol] :hash_key the index hash key column.
|
20
|
+
# @option options [Symbol] :range_key the index range key column (if
|
21
|
+
# applicable).
|
22
|
+
# @option options [Symbol, Array<Symbol>] :projected_attributes table
|
23
|
+
# attributes to project for this index. Can be :keys_only, :all
|
24
|
+
# or an array of included fields. If not specified, defaults to
|
25
|
+
# :keys_only.
|
26
|
+
# @option options [Integer] :read_capacity set the read capacity for the
|
27
|
+
# index; does not work on existing indexes.
|
28
|
+
# @option options [Integer] :write_capacity set the write capacity for
|
29
|
+
# the index; does not work on existing indexes.
|
30
|
+
def global_secondary_index(options={})
|
31
|
+
unless options.present?
|
32
|
+
raise Dynamoid::Errors::InvalidIndex.new('empty index definition')
|
33
|
+
end
|
34
|
+
|
35
|
+
unless options[:hash_key].present?
|
36
|
+
raise Dynamoid::Errors::InvalidIndex.new(
|
37
|
+
'A global secondary index requires a :hash_key to be specified'
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
index_opts = {
|
42
|
+
:read_capacity => Dynamoid::Config.read_capacity,
|
43
|
+
:write_capacity => Dynamoid::Config.write_capacity
|
44
|
+
}.merge(options)
|
45
|
+
|
46
|
+
index_opts[:dynamoid_class] = self
|
47
|
+
index_opts[:type] = :global_secondary
|
48
|
+
|
49
|
+
index = Dynamoid::Indexes::Index.new(index_opts)
|
50
|
+
gsi_key = index_key(options[:hash_key], options[:range_key])
|
51
|
+
self.global_secondary_indexes[gsi_key] = index
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Defines a local secondary index on a table. Will use the same primary
|
57
|
+
# hash key as the table.
|
58
|
+
#
|
59
|
+
# @param [Hash] options options to pass for this index.
|
60
|
+
# @option options [Symbol] :name the name for the index; this still gets
|
61
|
+
# namespaced. If not specified, a name is automatically generated.
|
62
|
+
# @option options [Symbol] :range_key the range key column for the index.
|
63
|
+
# @option options [Symbol, Array<Symbol>] :projected_attributes table
|
64
|
+
# attributes to project for this index. Can be :keys_only, :all
|
65
|
+
# or an array of included fields. If not specified, defaults to
|
66
|
+
# :keys_only.
|
67
|
+
def local_secondary_index(options={})
|
68
|
+
unless options.present?
|
69
|
+
raise Dynamoid::Errors::InvalidIndex.new('empty index definition')
|
70
|
+
end
|
71
|
+
|
72
|
+
primary_hash_key = self.hash_key
|
73
|
+
primary_range_key = self.range_key
|
74
|
+
index_range_key = options[:range_key]
|
75
|
+
|
76
|
+
unless index_range_key.present?
|
77
|
+
raise Dynamoid::Errors::InvalidIndex.new('A local secondary index '\
|
78
|
+
'requires a :range_key to be specified')
|
79
|
+
end
|
80
|
+
|
81
|
+
if primary_range_key.present? && index_range_key == primary_range_key
|
82
|
+
raise Dynamoid::Errors::InvalidIndex.new('A local secondary index'\
|
83
|
+
' must use a different :range_key than the primary key')
|
84
|
+
end
|
85
|
+
|
86
|
+
index_opts = options.merge({
|
87
|
+
:dynamoid_class => self,
|
88
|
+
:type => :local_secondary,
|
89
|
+
:hash_key => primary_hash_key
|
90
|
+
})
|
91
|
+
|
92
|
+
index = Dynamoid::Indexes::Index.new(index_opts)
|
93
|
+
key = index_key(primary_hash_key, index_range_key)
|
94
|
+
self.local_secondary_indexes[key] = index
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def find_index(hash, range=nil)
|
100
|
+
index = self.indexes[index_key(hash, range)]
|
101
|
+
index
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Returns true iff the provided hash[,range] key combo is a local
|
106
|
+
# secondary index.
|
107
|
+
#
|
108
|
+
# @param [Symbol] hash hash key name.
|
109
|
+
# @param [Symbol] range range key name.
|
110
|
+
# @return [Boolean] true iff provided keys correspond to a local
|
111
|
+
# secondary index.
|
112
|
+
def is_local_secondary_index?(hash, range=nil)
|
113
|
+
self.local_secondary_indexes[index_key(hash, range)].present?
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
# Returns true iff the provided hash[,range] key combo is a global
|
118
|
+
# secondary index.
|
119
|
+
#
|
120
|
+
# @param [Symbol] hash hash key name.
|
121
|
+
# @param [Symbol] range range key name.
|
122
|
+
# @return [Boolean] true iff provided keys correspond to a global
|
123
|
+
# secondary index.
|
124
|
+
def is_global_secondary_index?(hash, range=nil)
|
125
|
+
self.global_secondary_indexes[index_key(hash, range)].present?
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
# Generates a convenient lookup key name for a hash/range index.
|
130
|
+
# Should normally not be used directly.
|
131
|
+
#
|
132
|
+
# @param [Symbol] hash hash key name.
|
133
|
+
# @param [Symbol] range range key name.
|
134
|
+
# @return [String] returns "hash" if hash only, "hash_range" otherwise.
|
135
|
+
def index_key(hash, range=nil)
|
136
|
+
name = hash.to_s
|
137
|
+
if range.present?
|
138
|
+
name += "_#{range.to_s}"
|
139
|
+
end
|
140
|
+
name
|
141
|
+
end
|
142
|
+
|
143
|
+
|
144
|
+
# Generates a default index name.
|
145
|
+
#
|
146
|
+
# @param [Symbol] hash hash key name.
|
147
|
+
# @param [Symbol] range range key name.
|
148
|
+
# @return [String] index name of the form "table_name_index_index_key".
|
149
|
+
def index_name(hash, range=nil)
|
150
|
+
"#{self.table_name}_index_#{self.index_key(hash, range)}"
|
151
|
+
end
|
152
|
+
|
153
|
+
|
154
|
+
# Convenience method to return all indexes on the table.
|
155
|
+
#
|
156
|
+
# @return [Hash<String, Object>] the combined hash of global and local
|
157
|
+
# secondary indexes.
|
158
|
+
def indexes
|
159
|
+
self.local_secondary_indexes.merge(self.global_secondary_indexes)
|
160
|
+
end
|
161
|
+
|
162
|
+
def indexed_hash_keys
|
163
|
+
self.global_secondary_indexes.map do |name, index|
|
164
|
+
index.hash_key.to_s
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
|
170
|
+
# Represents the attributes of a DynamoDB index.
|
171
|
+
class Index
|
172
|
+
include ActiveModel::Validations
|
173
|
+
|
174
|
+
PROJECTION_TYPES = [:keys_only, :all].to_set
|
175
|
+
DEFAULT_PROJECTION_TYPE = :keys_only
|
176
|
+
|
177
|
+
attr_accessor :name, :dynamoid_class, :type, :hash_key, :range_key,
|
178
|
+
:hash_key_schema, :range_key_schema, :projected_attributes,
|
179
|
+
:read_capacity, :write_capacity
|
180
|
+
|
181
|
+
|
182
|
+
validate do
|
183
|
+
validate_index_type
|
184
|
+
validate_hash_key
|
185
|
+
validate_range_key
|
186
|
+
validate_projected_attributes
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
def initialize(attrs={})
|
191
|
+
unless attrs[:dynamoid_class].present?
|
192
|
+
raise Dynamoid::Errors::InvalidIndex.new(':dynamoid_class is required')
|
193
|
+
end
|
194
|
+
|
195
|
+
@dynamoid_class = attrs[:dynamoid_class]
|
196
|
+
@type = attrs[:type]
|
197
|
+
@hash_key = attrs[:hash_key]
|
198
|
+
@range_key = attrs[:range_key]
|
199
|
+
@name = attrs[:name] || @dynamoid_class.index_name(@hash_key, @range_key)
|
200
|
+
@projected_attributes =
|
201
|
+
attrs[:projected_attributes] || DEFAULT_PROJECTION_TYPE
|
202
|
+
@read_capacity = attrs[:read_capacity]
|
203
|
+
@write_capacity = attrs[:write_capacity]
|
204
|
+
|
205
|
+
raise Dynamoid::Errors::InvalidIndex.new(self) unless self.valid?
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
# Convenience method to determine the projection type for an index.
|
210
|
+
# Projection types are: :keys_only, :all, :include.
|
211
|
+
#
|
212
|
+
# @return [Symbol] the projection type.
|
213
|
+
def projection_type
|
214
|
+
if @projected_attributes.is_a? Array
|
215
|
+
:include
|
216
|
+
else
|
217
|
+
@projected_attributes
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
|
222
|
+
private
|
223
|
+
|
224
|
+
def validate_projected_attributes
|
225
|
+
unless (@projected_attributes.is_a?(Array) ||
|
226
|
+
PROJECTION_TYPES.include?(@projected_attributes))
|
227
|
+
errors.add(:projected_attributes, 'Invalid projected attributes specified.')
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def validate_index_type
|
232
|
+
unless (@type.present? &&
|
233
|
+
[:local_secondary, :global_secondary].include?(@type))
|
234
|
+
errors.add(:type, 'Invalid index :type specified')
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
def validate_range_key
|
239
|
+
if @range_key.present?
|
240
|
+
range_field_attributes = @dynamoid_class.attributes[@range_key]
|
241
|
+
if range_field_attributes.present?
|
242
|
+
range_key_type = range_field_attributes[:type]
|
243
|
+
if Dynamoid::Fields::PERMITTED_KEY_TYPES.include?(range_key_type)
|
244
|
+
@range_key_schema = {
|
245
|
+
@range_key => @dynamoid_class.dynamo_type(range_key_type)
|
246
|
+
}
|
247
|
+
else
|
248
|
+
errors.add(:range_key, 'Index :range_key is not a valid key type')
|
249
|
+
end
|
250
|
+
else
|
251
|
+
errors.add(:range_key, "No such field #{@range_key} defined on table")
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
def validate_hash_key
|
257
|
+
hash_field_attributes = @dynamoid_class.attributes[@hash_key]
|
258
|
+
if hash_field_attributes.present?
|
259
|
+
hash_field_type = hash_field_attributes[:type]
|
260
|
+
if Dynamoid::Fields::PERMITTED_KEY_TYPES.include?(hash_field_type)
|
261
|
+
@hash_key_schema = {
|
262
|
+
@hash_key => @dynamoid_class.dynamo_type(hash_field_type)
|
263
|
+
}
|
264
|
+
else
|
265
|
+
errors.add(:hash_key, 'Index :hash_key is not a valid key type')
|
266
|
+
end
|
267
|
+
else
|
268
|
+
errors.add(:hash_key, "No such field #{@hash_key} defined on table")
|
269
|
+
end
|
270
|
+
end
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dynamoid-edge
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josh Symonds
|
@@ -196,6 +196,7 @@ files:
|
|
196
196
|
- lib/dynamoid/fields.rb
|
197
197
|
- lib/dynamoid/finders.rb
|
198
198
|
- lib/dynamoid/identity_map.rb
|
199
|
+
- lib/dynamoid/indexes.rb
|
199
200
|
- lib/dynamoid/middleware/identity_map.rb
|
200
201
|
- lib/dynamoid/persistence.rb
|
201
202
|
- lib/dynamoid/validations.rb
|
@@ -219,8 +220,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
220
|
version: '0'
|
220
221
|
requirements: []
|
221
222
|
rubyforge_project:
|
222
|
-
rubygems_version: 2.4.5
|
223
|
+
rubygems_version: 2.4.5
|
223
224
|
signing_key:
|
224
225
|
specification_version: 4
|
225
226
|
summary: Dynamoid is an ORM for Amazon's DynamoDB
|
226
227
|
test_files: []
|
228
|
+
has_rdoc:
|