dynamoid-edge 1.1.0 → 1.1.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 +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:
|