dynamoid 0.7.1 → 1.0.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 +7 -0
- data/Gemfile +2 -24
- data/README.markdown +89 -73
- data/Rakefile +10 -36
- data/dynamoid.gemspec +56 -191
- data/lib/dynamoid.rb +6 -4
- data/lib/dynamoid/adapter.rb +64 -150
- data/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb +579 -0
- data/lib/dynamoid/components.rb +0 -1
- data/lib/dynamoid/config.rb +2 -5
- data/lib/dynamoid/criteria.rb +1 -1
- data/lib/dynamoid/criteria/chain.rb +27 -140
- data/lib/dynamoid/document.rb +2 -2
- data/lib/dynamoid/errors.rb +30 -9
- data/lib/dynamoid/fields.rb +15 -3
- data/lib/dynamoid/finders.rb +7 -6
- data/lib/dynamoid/identity_map.rb +1 -5
- data/lib/dynamoid/persistence.rb +108 -93
- metadata +56 -229
- data/.document +0 -5
- data/.rspec +0 -1
- data/.travis.yml +0 -7
- data/Gemfile.lock +0 -81
- data/Gemfile_activemodel4 +0 -24
- data/Gemfile_activemodel4.lock +0 -88
- data/VERSION +0 -1
- data/doc/.nojekyll +0 -0
- data/doc/Dynamoid.html +0 -328
- data/doc/Dynamoid/Adapter.html +0 -1872
- data/doc/Dynamoid/Adapter/AwsSdk.html +0 -2101
- data/doc/Dynamoid/Adapter/Local.html +0 -1574
- data/doc/Dynamoid/Associations.html +0 -138
- data/doc/Dynamoid/Associations/Association.html +0 -847
- data/doc/Dynamoid/Associations/BelongsTo.html +0 -161
- data/doc/Dynamoid/Associations/ClassMethods.html +0 -766
- data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +0 -167
- data/doc/Dynamoid/Associations/HasMany.html +0 -167
- data/doc/Dynamoid/Associations/HasOne.html +0 -161
- data/doc/Dynamoid/Associations/ManyAssociation.html +0 -1684
- data/doc/Dynamoid/Associations/SingleAssociation.html +0 -627
- data/doc/Dynamoid/Components.html +0 -242
- data/doc/Dynamoid/Config.html +0 -412
- data/doc/Dynamoid/Config/Options.html +0 -638
- data/doc/Dynamoid/Criteria.html +0 -138
- data/doc/Dynamoid/Criteria/Chain.html +0 -1471
- data/doc/Dynamoid/Criteria/ClassMethods.html +0 -105
- data/doc/Dynamoid/Dirty.html +0 -424
- data/doc/Dynamoid/Dirty/ClassMethods.html +0 -174
- data/doc/Dynamoid/Document.html +0 -1033
- data/doc/Dynamoid/Document/ClassMethods.html +0 -1116
- data/doc/Dynamoid/Errors.html +0 -125
- data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +0 -141
- data/doc/Dynamoid/Errors/DocumentNotValid.html +0 -221
- data/doc/Dynamoid/Errors/Error.html +0 -137
- data/doc/Dynamoid/Errors/InvalidField.html +0 -141
- data/doc/Dynamoid/Errors/InvalidQuery.html +0 -131
- data/doc/Dynamoid/Errors/MissingRangeKey.html +0 -141
- data/doc/Dynamoid/Fields.html +0 -686
- data/doc/Dynamoid/Fields/ClassMethods.html +0 -438
- data/doc/Dynamoid/Finders.html +0 -135
- data/doc/Dynamoid/Finders/ClassMethods.html +0 -943
- data/doc/Dynamoid/IdentityMap.html +0 -492
- data/doc/Dynamoid/IdentityMap/ClassMethods.html +0 -534
- data/doc/Dynamoid/Indexes.html +0 -321
- data/doc/Dynamoid/Indexes/ClassMethods.html +0 -369
- data/doc/Dynamoid/Indexes/Index.html +0 -1142
- data/doc/Dynamoid/Middleware.html +0 -115
- data/doc/Dynamoid/Middleware/IdentityMap.html +0 -264
- data/doc/Dynamoid/Persistence.html +0 -892
- data/doc/Dynamoid/Persistence/ClassMethods.html +0 -836
- data/doc/Dynamoid/Validations.html +0 -415
- data/doc/_index.html +0 -506
- data/doc/class_list.html +0 -53
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -57
- data/doc/css/style.css +0 -338
- data/doc/file.LICENSE.html +0 -73
- data/doc/file.README.html +0 -416
- data/doc/file_list.html +0 -58
- data/doc/frames.html +0 -28
- data/doc/index.html +0 -416
- data/doc/js/app.js +0 -214
- data/doc/js/full_list.js +0 -178
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -1144
- data/doc/top-level-namespace.html +0 -112
- data/lib/dynamoid/adapter/aws_sdk.rb +0 -287
- data/lib/dynamoid/indexes.rb +0 -69
- data/lib/dynamoid/indexes/index.rb +0 -103
- data/spec/app/models/address.rb +0 -13
- data/spec/app/models/camel_case.rb +0 -34
- data/spec/app/models/car.rb +0 -6
- data/spec/app/models/magazine.rb +0 -11
- data/spec/app/models/message.rb +0 -9
- data/spec/app/models/nuclear_submarine.rb +0 -5
- data/spec/app/models/sponsor.rb +0 -8
- data/spec/app/models/subscription.rb +0 -12
- data/spec/app/models/tweet.rb +0 -12
- data/spec/app/models/user.rb +0 -26
- data/spec/app/models/vehicle.rb +0 -7
- data/spec/dynamoid/adapter/aws_sdk_spec.rb +0 -376
- data/spec/dynamoid/adapter_spec.rb +0 -155
- data/spec/dynamoid/associations/association_spec.rb +0 -194
- data/spec/dynamoid/associations/belongs_to_spec.rb +0 -71
- data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +0 -47
- data/spec/dynamoid/associations/has_many_spec.rb +0 -42
- data/spec/dynamoid/associations/has_one_spec.rb +0 -45
- data/spec/dynamoid/associations_spec.rb +0 -16
- data/spec/dynamoid/config_spec.rb +0 -27
- data/spec/dynamoid/criteria/chain_spec.rb +0 -210
- data/spec/dynamoid/criteria_spec.rb +0 -75
- data/spec/dynamoid/dirty_spec.rb +0 -57
- data/spec/dynamoid/document_spec.rb +0 -180
- data/spec/dynamoid/fields_spec.rb +0 -156
- data/spec/dynamoid/finders_spec.rb +0 -147
- data/spec/dynamoid/identity_map_spec.rb +0 -45
- data/spec/dynamoid/indexes/index_spec.rb +0 -104
- data/spec/dynamoid/indexes_spec.rb +0 -25
- data/spec/dynamoid/persistence_spec.rb +0 -301
- data/spec/dynamoid/validations_spec.rb +0 -36
- data/spec/dynamoid_spec.rb +0 -9
- data/spec/spec_helper.rb +0 -55
- data/spec/support/with_partitioning.rb +0 -15
data/lib/dynamoid/components.rb
CHANGED
data/lib/dynamoid/config.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Dynamoid
|
|
|
11
11
|
include ActiveModel::Observing if defined?(ActiveModel::Observing)
|
|
12
12
|
|
|
13
13
|
# All the default options.
|
|
14
|
-
option :adapter, :default => '
|
|
14
|
+
option :adapter, :default => 'aws_sdk_v2'
|
|
15
15
|
option :namespace, :default => defined?(Rails) ? "dynamoid_#{Rails.application.class.parent_name}_#{Rails.env}" : "dynamoid"
|
|
16
16
|
option :logger, :default => defined?(Rails)
|
|
17
17
|
option :access_key
|
|
@@ -19,12 +19,9 @@ module Dynamoid
|
|
|
19
19
|
option :read_capacity, :default => 100
|
|
20
20
|
option :write_capacity, :default => 20
|
|
21
21
|
option :warn_on_scan, :default => true
|
|
22
|
-
option :
|
|
23
|
-
option :partition_size, :default => 200
|
|
24
|
-
option :endpoint, :default => 'dynamodb.us-east-1.amazonaws.com'
|
|
22
|
+
option :endpoint, :default => nil
|
|
25
23
|
option :use_ssl, :default => true
|
|
26
24
|
option :port, :default => '443'
|
|
27
|
-
option :included_models, :default => []
|
|
28
25
|
option :identity_map, :default => false
|
|
29
26
|
|
|
30
27
|
# The default logger for Dynamoid: either the Rails logger or just stdout.
|
data/lib/dynamoid/criteria.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Dynamoid
|
|
|
9
9
|
|
|
10
10
|
module ClassMethods
|
|
11
11
|
|
|
12
|
-
[:where, :all, :first, :each, :
|
|
12
|
+
[:where, :all, :first, :each, :eval_limit, :start, :scan_index_forward].each do |meth|
|
|
13
13
|
# Return a criteria chain in response to a method that will begin or end a chain. For more information,
|
|
14
14
|
# see Dynamoid::Criteria::Chain.
|
|
15
15
|
#
|
|
@@ -3,10 +3,9 @@ module Dynamoid #:nodoc:
|
|
|
3
3
|
module Criteria
|
|
4
4
|
|
|
5
5
|
# The criteria chain is equivalent to an ActiveRecord relation (and realistically I should change the name from
|
|
6
|
-
# chain to relation). It is a chainable object that builds up a query and eventually executes it
|
|
7
|
-
# or by a full table scan.
|
|
6
|
+
# chain to relation). It is a chainable object that builds up a query and eventually executes it by a Query or Scan.
|
|
8
7
|
class Chain
|
|
9
|
-
attr_accessor :query, :source, :
|
|
8
|
+
attr_accessor :query, :source, :values, :consistent_read
|
|
10
9
|
include Enumerable
|
|
11
10
|
|
|
12
11
|
# Create a new criteria chain.
|
|
@@ -43,82 +42,38 @@ module Dynamoid #:nodoc:
|
|
|
43
42
|
# Returns all the records matching the criteria.
|
|
44
43
|
#
|
|
45
44
|
# @since 0.2.0
|
|
46
|
-
def all
|
|
47
|
-
batch opts[:batch_size] if opts.has_key? :batch_size
|
|
45
|
+
def all
|
|
48
46
|
records
|
|
49
47
|
end
|
|
50
|
-
|
|
48
|
+
|
|
51
49
|
# Destroys all the records matching the criteria.
|
|
52
50
|
#
|
|
53
51
|
def destroy_all
|
|
54
52
|
ids = []
|
|
55
53
|
|
|
56
|
-
if
|
|
54
|
+
if key_present?
|
|
57
55
|
ranges = []
|
|
58
|
-
Dynamoid
|
|
56
|
+
Dynamoid.adapter.query(source.table_name, range_query).collect do |hash|
|
|
59
57
|
ids << hash[source.hash_key.to_sym]
|
|
60
58
|
ranges << hash[source.range_key.to_sym]
|
|
61
59
|
end
|
|
62
60
|
|
|
63
|
-
Dynamoid
|
|
64
|
-
elsif index
|
|
65
|
-
#TODO: test this throughly and find a way to delete all index table records for one source record
|
|
66
|
-
if index.range_key?
|
|
67
|
-
results = Dynamoid::Adapter.query(index.table_name, index_query.merge(consistent_opts))
|
|
68
|
-
else
|
|
69
|
-
results = Dynamoid::Adapter.read(index.table_name, index_query[:hash_value], consistent_opts)
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
results.collect do |hash|
|
|
73
|
-
ids << hash[source.hash_key.to_sym]
|
|
74
|
-
index_ranges << hash[source.range_key.to_sym]
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
unless ids.nil? || ids.empty?
|
|
78
|
-
ids = ids.to_a
|
|
79
|
-
|
|
80
|
-
if @start
|
|
81
|
-
ids = ids.drop_while { |id| id != @start.hash_key }.drop(1)
|
|
82
|
-
index_ranges = index_ranges.drop_while { |range| range != @start.hash_key }.drop(1) unless index_ranges.nil?
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
if @limit
|
|
86
|
-
ids = ids.take(@limit)
|
|
87
|
-
index_ranges = index_ranges.take(@limit)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
Dynamoid::Adapter.delete(source.table_name, ids)
|
|
91
|
-
|
|
92
|
-
if index.range_key?
|
|
93
|
-
Dynamoid::Adapter.delete(index.table_name, ids,{:range_key => index_ranges})
|
|
94
|
-
else
|
|
95
|
-
Dynamoid::Adapter.delete(index.table_name, ids)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
end
|
|
61
|
+
Dynamoid.adapter.delete(source.table_name, ids,{:range_key => ranges})
|
|
99
62
|
else
|
|
100
|
-
Dynamoid
|
|
63
|
+
Dynamoid.adapter.scan(source.table_name, query, scan_opts).collect do |hash|
|
|
101
64
|
ids << hash[source.hash_key.to_sym]
|
|
102
65
|
end
|
|
103
66
|
|
|
104
|
-
Dynamoid
|
|
67
|
+
Dynamoid.adapter.delete(source.table_name, ids)
|
|
105
68
|
end
|
|
106
69
|
end
|
|
107
70
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def first
|
|
112
|
-
limit(1).first
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
def limit(limit)
|
|
116
|
-
@limit = limit
|
|
117
|
-
records
|
|
71
|
+
def eval_limit(limit)
|
|
72
|
+
@eval_limit = limit
|
|
73
|
+
self
|
|
118
74
|
end
|
|
119
75
|
|
|
120
76
|
def batch(batch_size)
|
|
121
|
-
raise 'Cannot batch calls when using partitioning' if Dynamoid::Config.partitioning?
|
|
122
77
|
@batch_size = batch_size
|
|
123
78
|
self
|
|
124
79
|
end
|
|
@@ -152,54 +107,17 @@ module Dynamoid #:nodoc:
|
|
|
152
107
|
#
|
|
153
108
|
# @since 0.2.0
|
|
154
109
|
def records
|
|
155
|
-
results = if
|
|
156
|
-
|
|
157
|
-
elsif index
|
|
158
|
-
records_with_index
|
|
110
|
+
results = if key_present?
|
|
111
|
+
records_via_query
|
|
159
112
|
else
|
|
160
|
-
|
|
113
|
+
records_via_scan
|
|
161
114
|
end
|
|
162
115
|
@batch_size ? results : Array(results)
|
|
163
116
|
end
|
|
164
117
|
|
|
165
|
-
|
|
166
|
-
#
|
|
167
|
-
# @return [Enumerator] an iterator of the found records.
|
|
168
|
-
#
|
|
169
|
-
# @since 0.2.0
|
|
170
|
-
def records_with_index
|
|
171
|
-
ids = ids_from_index
|
|
172
|
-
if ids.nil? || ids.empty?
|
|
173
|
-
Enumerator.new []
|
|
174
|
-
else
|
|
175
|
-
ids = ids.to_a
|
|
176
|
-
|
|
177
|
-
if @start
|
|
178
|
-
ids = ids.drop_while { |id| id != @start.hash_key }.drop(1)
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
ids = ids.take(@limit) if @limit
|
|
182
|
-
source.find(ids, consistent_opts)
|
|
183
|
-
end
|
|
184
|
-
end
|
|
185
|
-
|
|
186
|
-
# Returns the Set of IDs from the index table.
|
|
187
|
-
#
|
|
188
|
-
# @return [Set] a Set containing the IDs from the index.
|
|
189
|
-
def ids_from_index
|
|
190
|
-
if index.range_key?
|
|
191
|
-
Dynamoid::Adapter.query(index.table_name, index_query.merge(consistent_opts)).inject(Set.new) do |all, record|
|
|
192
|
-
all + Set.new(record[:ids])
|
|
193
|
-
end
|
|
194
|
-
else
|
|
195
|
-
results = Dynamoid::Adapter.read(index.table_name, index_query[:hash_value], consistent_opts)
|
|
196
|
-
results ? results[:ids] : []
|
|
197
|
-
end
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def records_with_range
|
|
118
|
+
def records_via_query
|
|
201
119
|
Enumerator.new do |yielder|
|
|
202
|
-
Dynamoid
|
|
120
|
+
Dynamoid.adapter.query(source.table_name, range_query).each do |hash|
|
|
203
121
|
yielder.yield source.from_database(hash)
|
|
204
122
|
end
|
|
205
123
|
end
|
|
@@ -210,7 +128,7 @@ module Dynamoid #:nodoc:
|
|
|
210
128
|
# @return [Enumerator] an iterator of the found records.
|
|
211
129
|
#
|
|
212
130
|
# @since 0.2.0
|
|
213
|
-
def
|
|
131
|
+
def records_via_scan
|
|
214
132
|
if Dynamoid::Config.warn_on_scan
|
|
215
133
|
Dynamoid.logger.warn 'Queries without an index are forced to use scan and are generally much slower than indexed queries!'
|
|
216
134
|
Dynamoid.logger.warn "You can index this query by adding this to #{source.to_s.downcase}.rb: index [#{source.attributes.sort.collect{|attr| ":#{attr}"}.join(', ')}]"
|
|
@@ -221,38 +139,18 @@ module Dynamoid #:nodoc:
|
|
|
221
139
|
end
|
|
222
140
|
|
|
223
141
|
Enumerator.new do |yielder|
|
|
224
|
-
Dynamoid
|
|
142
|
+
Dynamoid.adapter.scan(source.table_name, query, scan_opts).each do |hash|
|
|
225
143
|
yielder.yield source.from_database(hash)
|
|
226
144
|
end
|
|
227
145
|
end
|
|
228
146
|
end
|
|
229
147
|
|
|
230
|
-
# Format the provided query so that it can be used to query results from DynamoDB.
|
|
231
|
-
#
|
|
232
|
-
# @return [Hash] a hash with keys of :hash_value and :range_value
|
|
233
|
-
#
|
|
234
|
-
# @since 0.2.0
|
|
235
|
-
def index_query
|
|
236
|
-
values = index.values(query)
|
|
237
|
-
{}.tap do |hash|
|
|
238
|
-
hash[:hash_value] = values[:hash_value]
|
|
239
|
-
if index.range_key?
|
|
240
|
-
key = query.keys.find{|k| k.to_s.include?('.')}
|
|
241
|
-
if key
|
|
242
|
-
hash.merge!(range_hash(key))
|
|
243
|
-
else
|
|
244
|
-
raise Dynamoid::Errors::MissingRangeKey, 'This index requires a range key'
|
|
245
|
-
end
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
148
|
def range_hash(key)
|
|
251
149
|
val = query[key]
|
|
252
150
|
|
|
253
151
|
return { :range_value => query[key] } if query[key].is_a?(Range)
|
|
254
152
|
|
|
255
|
-
case key.split('.').last
|
|
153
|
+
case key.to_s.split('.').last
|
|
256
154
|
when 'gt'
|
|
257
155
|
{ :range_greater_than => val.to_f }
|
|
258
156
|
when 'lt'
|
|
@@ -274,38 +172,27 @@ module Dynamoid #:nodoc:
|
|
|
274
172
|
opts.merge(query_opts).merge(consistent_opts)
|
|
275
173
|
end
|
|
276
174
|
|
|
277
|
-
# Return an index that fulfills all the attributes the criteria is querying, or nil if none is found.
|
|
278
|
-
#
|
|
279
|
-
# @since 0.2.0
|
|
280
|
-
def index
|
|
281
|
-
index = source.find_index(query_keys)
|
|
282
|
-
return nil if index.blank?
|
|
283
|
-
index
|
|
284
|
-
end
|
|
285
|
-
|
|
286
175
|
def query_keys
|
|
287
176
|
query.keys.collect{|k| k.to_s.split('.').first}
|
|
288
177
|
end
|
|
289
178
|
|
|
290
|
-
#
|
|
291
|
-
def
|
|
292
|
-
return false unless query_keys.include?(source.hash_key.to_s) or query_keys.include?(source.range_key.to_s)
|
|
179
|
+
# [hash_key] or [hash_key, range_key] is specified in query keys.
|
|
180
|
+
def key_present?
|
|
293
181
|
query_keys == [source.hash_key.to_s] || (query_keys.to_set == [source.hash_key.to_s, source.range_key.to_s].to_set)
|
|
294
182
|
end
|
|
295
183
|
|
|
296
184
|
def start_key
|
|
297
|
-
|
|
298
|
-
key = { :hash_key_element => { hash_key_type => @start.hash_key.to_s } }
|
|
185
|
+
key = { :hash_key_element => @start.hash_key }
|
|
299
186
|
if range_key = @start.class.range_key
|
|
300
|
-
|
|
301
|
-
key.merge!({:range_key_element => { range_key_type => @start.send(range_key).to_s } })
|
|
187
|
+
key.merge!({:range_key_element => @start.send(range_key) })
|
|
302
188
|
end
|
|
303
189
|
key
|
|
304
190
|
end
|
|
305
191
|
|
|
306
192
|
def query_opts
|
|
307
193
|
opts = {}
|
|
308
|
-
opts[:
|
|
194
|
+
opts[:select] = 'ALL_ATTRIBUTES'
|
|
195
|
+
opts[:limit] = @eval_limit if @eval_limit
|
|
309
196
|
opts[:next_token] = start_key if @start
|
|
310
197
|
opts[:scan_index_forward] = @scan_index_forward
|
|
311
198
|
opts
|
|
@@ -313,7 +200,7 @@ module Dynamoid #:nodoc:
|
|
|
313
200
|
|
|
314
201
|
def scan_opts
|
|
315
202
|
opts = {}
|
|
316
|
-
opts[:limit] = @
|
|
203
|
+
opts[:limit] = @eval_limit if @eval_limit
|
|
317
204
|
opts[:next_token] = start_key if @start
|
|
318
205
|
opts[:batch_size] = @batch_size if @batch_size
|
|
319
206
|
opts
|
data/lib/dynamoid/document.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Dynamoid #:nodoc:
|
|
|
13
13
|
self.read_only_attributes = []
|
|
14
14
|
self.base_class = self
|
|
15
15
|
|
|
16
|
-
Dynamoid
|
|
16
|
+
Dynamoid.included_models << self
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
module ClassMethods
|
|
@@ -61,7 +61,7 @@ module Dynamoid #:nodoc:
|
|
|
61
61
|
#
|
|
62
62
|
# @since 0.6.1
|
|
63
63
|
def count
|
|
64
|
-
Dynamoid
|
|
64
|
+
Dynamoid.adapter.count(table_name)
|
|
65
65
|
end
|
|
66
66
|
|
|
67
67
|
# Initialize a new object and immediately save it to the database.
|
data/lib/dynamoid/errors.rb
CHANGED
|
@@ -1,22 +1,43 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
module Dynamoid
|
|
3
3
|
|
|
4
|
-
# All the
|
|
4
|
+
# All the errors specific to Dynamoid. The goal is to mimic ActiveRecord.
|
|
5
5
|
module Errors
|
|
6
6
|
|
|
7
|
-
# Generic error
|
|
7
|
+
# Generic Dynamoid error
|
|
8
8
|
class Error < StandardError; end
|
|
9
9
|
|
|
10
|
-
# InvalidField is raised when an attribute is specified for an index, but the attribute does not exist.
|
|
11
|
-
class InvalidField < Error; end
|
|
12
|
-
|
|
13
|
-
# MissingRangeKey is raised when a table that requires a range key is quieried without one.
|
|
14
10
|
class MissingRangeKey < Error; end
|
|
15
11
|
|
|
16
|
-
#
|
|
17
|
-
class ConditionalCheckFailedException < Error
|
|
12
|
+
# This class is intended to be private to Dynamoid.
|
|
13
|
+
class ConditionalCheckFailedException < Error
|
|
14
|
+
attr_reader :inner_exception
|
|
15
|
+
|
|
16
|
+
def initialize(inner)
|
|
17
|
+
super
|
|
18
|
+
@inner_exception = inner
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class RecordNotUnique < ConditionalCheckFailedException
|
|
23
|
+
attr_reader :original_exception
|
|
24
|
+
|
|
25
|
+
def initialize(original_exception, record)
|
|
26
|
+
super("Attempted to write record #{record} when its key already exists")
|
|
27
|
+
@original_exception = original_exception
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
class StaleObjectError < ConditionalCheckFailedException
|
|
32
|
+
attr_reader :record, :attempted_action
|
|
33
|
+
|
|
34
|
+
def initialize(record, attempted_action)
|
|
35
|
+
super("Attempted to #{attempted_action} a stale object #{record}")
|
|
36
|
+
@record = record
|
|
37
|
+
@attempted_action = attempted_action
|
|
38
|
+
end
|
|
39
|
+
end
|
|
18
40
|
|
|
19
|
-
# DocumentNotValid is raised when the document fails validation.
|
|
20
41
|
class DocumentNotValid < Error
|
|
21
42
|
def initialize(document)
|
|
22
43
|
super("Validation failed: #{document.errors.full_messages.join(", ")}")
|
data/lib/dynamoid/fields.rb
CHANGED
|
@@ -20,16 +20,28 @@ module Dynamoid #:nodoc:
|
|
|
20
20
|
|
|
21
21
|
module ClassMethods
|
|
22
22
|
|
|
23
|
-
# Specify a field for a document.
|
|
24
|
-
#
|
|
23
|
+
# Specify a field for a document.
|
|
24
|
+
#
|
|
25
|
+
# Its type determines how it is coerced when read in and out of the datastore.
|
|
26
|
+
# You can specify :integer, :number, :set, :array, :datetime, and :serialized,
|
|
27
|
+
# or specify a class that defines a serialization strategy.
|
|
28
|
+
#
|
|
29
|
+
# If you specify a class for field type, Dynamoid will serialize using
|
|
30
|
+
# `dynamoid_dump` or `dump` methods, and load using `dynamoid_load` or `load` methods.
|
|
31
|
+
#
|
|
32
|
+
# Default field type is :string.
|
|
25
33
|
#
|
|
26
34
|
# @param [Symbol] name the name of the field
|
|
27
|
-
# @param [Symbol] type the type of the field (
|
|
35
|
+
# @param [Symbol] type the type of the field (refer to method description for details)
|
|
28
36
|
# @param [Hash] options any additional options for the field
|
|
29
37
|
#
|
|
30
38
|
# @since 0.2.0
|
|
31
39
|
def field(name, type = :string, options = {})
|
|
32
40
|
named = name.to_s
|
|
41
|
+
if type == :float
|
|
42
|
+
Dynamoid.logger.warn("Field type :float, which you declared for '#{name}', is deprecated in favor of :number.")
|
|
43
|
+
type = :number
|
|
44
|
+
end
|
|
33
45
|
self.attributes = attributes.merge(name => {:type => type}.merge(options))
|
|
34
46
|
|
|
35
47
|
define_method(named) { read_attribute(named) }
|
data/lib/dynamoid/finders.rb
CHANGED
|
@@ -16,16 +16,17 @@ module Dynamoid
|
|
|
16
16
|
#
|
|
17
17
|
# @since 0.2.0
|
|
18
18
|
def find(*ids)
|
|
19
|
-
|
|
20
19
|
options = if ids.last.is_a? Hash
|
|
21
20
|
ids.slice!(-1)
|
|
22
21
|
else
|
|
23
22
|
{}
|
|
24
23
|
end
|
|
24
|
+
expects_array = ids.first.kind_of?(Array)
|
|
25
25
|
|
|
26
26
|
ids = Array(ids.flatten.uniq)
|
|
27
27
|
if ids.count == 1
|
|
28
|
-
self.find_by_id(ids.first, options)
|
|
28
|
+
result = self.find_by_id(ids.first, options)
|
|
29
|
+
expects_array ? Array(result) : result
|
|
29
30
|
else
|
|
30
31
|
find_all(ids)
|
|
31
32
|
end
|
|
@@ -44,7 +45,7 @@ module Dynamoid
|
|
|
44
45
|
# find all the tweets using hash key and range key with consistent read
|
|
45
46
|
# Tweet.find_all([['1', 'red'], ['1', 'green']], :consistent_read => true)
|
|
46
47
|
def find_all(ids, options = {})
|
|
47
|
-
items = Dynamoid
|
|
48
|
+
items = Dynamoid.adapter.read(self.table_name, ids, options)
|
|
48
49
|
items ? items[self.table_name].map{|i| from_database(i)} : []
|
|
49
50
|
end
|
|
50
51
|
|
|
@@ -56,7 +57,7 @@ module Dynamoid
|
|
|
56
57
|
#
|
|
57
58
|
# @since 0.2.0
|
|
58
59
|
def find_by_id(id, options = {})
|
|
59
|
-
if item = Dynamoid
|
|
60
|
+
if item = Dynamoid.adapter.read(self.table_name, id, options)
|
|
60
61
|
from_database(item)
|
|
61
62
|
else
|
|
62
63
|
nil
|
|
@@ -66,7 +67,7 @@ module Dynamoid
|
|
|
66
67
|
# Find one object directly by hash and range keys
|
|
67
68
|
#
|
|
68
69
|
# @param [String] hash_key of the object to find
|
|
69
|
-
# @param [String/
|
|
70
|
+
# @param [String/Number] range_key of the object to find
|
|
70
71
|
#
|
|
71
72
|
def find_by_composite_key(hash_key, range_key, options = {})
|
|
72
73
|
find_by_id(hash_key, options.merge({:range_key => range_key}))
|
|
@@ -94,7 +95,7 @@ module Dynamoid
|
|
|
94
95
|
# @return [Array] an array of all matching items
|
|
95
96
|
#
|
|
96
97
|
def find_all_by_composite_key(hash_key, options = {})
|
|
97
|
-
Dynamoid
|
|
98
|
+
Dynamoid.adapter.query(self.table_name, options.merge({hash_value: hash_key})).collect do |item|
|
|
98
99
|
from_database(item)
|
|
99
100
|
end
|
|
100
101
|
end
|