dynamoid 0.7.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +2 -24
  3. data/README.markdown +89 -73
  4. data/Rakefile +10 -36
  5. data/dynamoid.gemspec +56 -191
  6. data/lib/dynamoid.rb +6 -4
  7. data/lib/dynamoid/adapter.rb +64 -150
  8. data/lib/dynamoid/adapter_plugin/aws_sdk_v2.rb +579 -0
  9. data/lib/dynamoid/components.rb +0 -1
  10. data/lib/dynamoid/config.rb +2 -5
  11. data/lib/dynamoid/criteria.rb +1 -1
  12. data/lib/dynamoid/criteria/chain.rb +27 -140
  13. data/lib/dynamoid/document.rb +2 -2
  14. data/lib/dynamoid/errors.rb +30 -9
  15. data/lib/dynamoid/fields.rb +15 -3
  16. data/lib/dynamoid/finders.rb +7 -6
  17. data/lib/dynamoid/identity_map.rb +1 -5
  18. data/lib/dynamoid/persistence.rb +108 -93
  19. metadata +56 -229
  20. data/.document +0 -5
  21. data/.rspec +0 -1
  22. data/.travis.yml +0 -7
  23. data/Gemfile.lock +0 -81
  24. data/Gemfile_activemodel4 +0 -24
  25. data/Gemfile_activemodel4.lock +0 -88
  26. data/VERSION +0 -1
  27. data/doc/.nojekyll +0 -0
  28. data/doc/Dynamoid.html +0 -328
  29. data/doc/Dynamoid/Adapter.html +0 -1872
  30. data/doc/Dynamoid/Adapter/AwsSdk.html +0 -2101
  31. data/doc/Dynamoid/Adapter/Local.html +0 -1574
  32. data/doc/Dynamoid/Associations.html +0 -138
  33. data/doc/Dynamoid/Associations/Association.html +0 -847
  34. data/doc/Dynamoid/Associations/BelongsTo.html +0 -161
  35. data/doc/Dynamoid/Associations/ClassMethods.html +0 -766
  36. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +0 -167
  37. data/doc/Dynamoid/Associations/HasMany.html +0 -167
  38. data/doc/Dynamoid/Associations/HasOne.html +0 -161
  39. data/doc/Dynamoid/Associations/ManyAssociation.html +0 -1684
  40. data/doc/Dynamoid/Associations/SingleAssociation.html +0 -627
  41. data/doc/Dynamoid/Components.html +0 -242
  42. data/doc/Dynamoid/Config.html +0 -412
  43. data/doc/Dynamoid/Config/Options.html +0 -638
  44. data/doc/Dynamoid/Criteria.html +0 -138
  45. data/doc/Dynamoid/Criteria/Chain.html +0 -1471
  46. data/doc/Dynamoid/Criteria/ClassMethods.html +0 -105
  47. data/doc/Dynamoid/Dirty.html +0 -424
  48. data/doc/Dynamoid/Dirty/ClassMethods.html +0 -174
  49. data/doc/Dynamoid/Document.html +0 -1033
  50. data/doc/Dynamoid/Document/ClassMethods.html +0 -1116
  51. data/doc/Dynamoid/Errors.html +0 -125
  52. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +0 -141
  53. data/doc/Dynamoid/Errors/DocumentNotValid.html +0 -221
  54. data/doc/Dynamoid/Errors/Error.html +0 -137
  55. data/doc/Dynamoid/Errors/InvalidField.html +0 -141
  56. data/doc/Dynamoid/Errors/InvalidQuery.html +0 -131
  57. data/doc/Dynamoid/Errors/MissingRangeKey.html +0 -141
  58. data/doc/Dynamoid/Fields.html +0 -686
  59. data/doc/Dynamoid/Fields/ClassMethods.html +0 -438
  60. data/doc/Dynamoid/Finders.html +0 -135
  61. data/doc/Dynamoid/Finders/ClassMethods.html +0 -943
  62. data/doc/Dynamoid/IdentityMap.html +0 -492
  63. data/doc/Dynamoid/IdentityMap/ClassMethods.html +0 -534
  64. data/doc/Dynamoid/Indexes.html +0 -321
  65. data/doc/Dynamoid/Indexes/ClassMethods.html +0 -369
  66. data/doc/Dynamoid/Indexes/Index.html +0 -1142
  67. data/doc/Dynamoid/Middleware.html +0 -115
  68. data/doc/Dynamoid/Middleware/IdentityMap.html +0 -264
  69. data/doc/Dynamoid/Persistence.html +0 -892
  70. data/doc/Dynamoid/Persistence/ClassMethods.html +0 -836
  71. data/doc/Dynamoid/Validations.html +0 -415
  72. data/doc/_index.html +0 -506
  73. data/doc/class_list.html +0 -53
  74. data/doc/css/common.css +0 -1
  75. data/doc/css/full_list.css +0 -57
  76. data/doc/css/style.css +0 -338
  77. data/doc/file.LICENSE.html +0 -73
  78. data/doc/file.README.html +0 -416
  79. data/doc/file_list.html +0 -58
  80. data/doc/frames.html +0 -28
  81. data/doc/index.html +0 -416
  82. data/doc/js/app.js +0 -214
  83. data/doc/js/full_list.js +0 -178
  84. data/doc/js/jquery.js +0 -4
  85. data/doc/method_list.html +0 -1144
  86. data/doc/top-level-namespace.html +0 -112
  87. data/lib/dynamoid/adapter/aws_sdk.rb +0 -287
  88. data/lib/dynamoid/indexes.rb +0 -69
  89. data/lib/dynamoid/indexes/index.rb +0 -103
  90. data/spec/app/models/address.rb +0 -13
  91. data/spec/app/models/camel_case.rb +0 -34
  92. data/spec/app/models/car.rb +0 -6
  93. data/spec/app/models/magazine.rb +0 -11
  94. data/spec/app/models/message.rb +0 -9
  95. data/spec/app/models/nuclear_submarine.rb +0 -5
  96. data/spec/app/models/sponsor.rb +0 -8
  97. data/spec/app/models/subscription.rb +0 -12
  98. data/spec/app/models/tweet.rb +0 -12
  99. data/spec/app/models/user.rb +0 -26
  100. data/spec/app/models/vehicle.rb +0 -7
  101. data/spec/dynamoid/adapter/aws_sdk_spec.rb +0 -376
  102. data/spec/dynamoid/adapter_spec.rb +0 -155
  103. data/spec/dynamoid/associations/association_spec.rb +0 -194
  104. data/spec/dynamoid/associations/belongs_to_spec.rb +0 -71
  105. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +0 -47
  106. data/spec/dynamoid/associations/has_many_spec.rb +0 -42
  107. data/spec/dynamoid/associations/has_one_spec.rb +0 -45
  108. data/spec/dynamoid/associations_spec.rb +0 -16
  109. data/spec/dynamoid/config_spec.rb +0 -27
  110. data/spec/dynamoid/criteria/chain_spec.rb +0 -210
  111. data/spec/dynamoid/criteria_spec.rb +0 -75
  112. data/spec/dynamoid/dirty_spec.rb +0 -57
  113. data/spec/dynamoid/document_spec.rb +0 -180
  114. data/spec/dynamoid/fields_spec.rb +0 -156
  115. data/spec/dynamoid/finders_spec.rb +0 -147
  116. data/spec/dynamoid/identity_map_spec.rb +0 -45
  117. data/spec/dynamoid/indexes/index_spec.rb +0 -104
  118. data/spec/dynamoid/indexes_spec.rb +0 -25
  119. data/spec/dynamoid/persistence_spec.rb +0 -301
  120. data/spec/dynamoid/validations_spec.rb +0 -36
  121. data/spec/dynamoid_spec.rb +0 -9
  122. data/spec/spec_helper.rb +0 -55
  123. data/spec/support/with_partitioning.rb +0 -15
@@ -25,7 +25,6 @@ module Dynamoid
25
25
  include ActiveModel::Serializers::JSON
26
26
  include ActiveModel::Serializers::Xml
27
27
  include Dynamoid::Fields
28
- include Dynamoid::Indexes
29
28
  include Dynamoid::Persistence
30
29
  include Dynamoid::Finders
31
30
  include Dynamoid::Associations
@@ -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 => 'aws-sdk'
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 :partitioning, :default => false
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.
@@ -9,7 +9,7 @@ module Dynamoid
9
9
 
10
10
  module ClassMethods
11
11
 
12
- [:where, :all, :first, :each, :limit, :start, :scan_index_forward].each do |meth|
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 either on an index
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, :index, :values, :limit, :start, :consistent_read
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(opts = {})
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 range?
54
+ if key_present?
57
55
  ranges = []
58
- Dynamoid::Adapter.query(source.table_name, range_query).collect do |hash|
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::Adapter.delete(source.table_name, ids,{:range_key => ranges})
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::Adapter.scan(source.table_name, query, scan_opts).collect do |hash|
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::Adapter.delete(source.table_name, ids)
67
+ Dynamoid.adapter.delete(source.table_name, ids)
105
68
  end
106
69
  end
107
70
 
108
- # Returns the first record matching the criteria.
109
- #
110
- # @since 0.2.0
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 range?
156
- records_with_range
157
- elsif index
158
- records_with_index
110
+ results = if key_present?
111
+ records_via_query
159
112
  else
160
- records_without_index
113
+ records_via_scan
161
114
  end
162
115
  @batch_size ? results : Array(results)
163
116
  end
164
117
 
165
- # If the query matches an index on the associated class, then this method will retrieve results from the index table.
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::Adapter.query(source.table_name, range_query).each do |hash|
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 records_without_index
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::Adapter.scan(source.table_name, query, scan_opts).each do |hash|
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
- # Use range query only when [hash_key] or [hash_key, range_key] is specified in query keys.
291
- def range?
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
- hash_key_type = @start.class.attributes[@start.class.hash_key][:type] == :string ? 'S' : 'N'
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
- range_key_type = @start.class.attributes[range_key][:type] == :string ? 'S' : 'N'
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[:limit] = @limit if @limit
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] = @limit if @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
@@ -13,7 +13,7 @@ module Dynamoid #:nodoc:
13
13
  self.read_only_attributes = []
14
14
  self.base_class = self
15
15
 
16
- Dynamoid::Config.included_models << self
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::Adapter::AwsSdk.count(table_name)
64
+ Dynamoid.adapter.count(table_name)
65
65
  end
66
66
 
67
67
  # Initialize a new object and immediately save it to the database.
@@ -1,22 +1,43 @@
1
1
  # encoding: utf-8
2
2
  module Dynamoid
3
3
 
4
- # All the error specific to Dynamoid.
4
+ # All the errors specific to Dynamoid. The goal is to mimic ActiveRecord.
5
5
  module Errors
6
6
 
7
- # Generic error class.
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
- # raised when the conditional check failed during update operation
17
- class ConditionalCheckFailedException < Error; end
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(", ")}")
@@ -20,16 +20,28 @@ module Dynamoid #:nodoc:
20
20
 
21
21
  module ClassMethods
22
22
 
23
- # Specify a field for a document. Its type determines how it is coerced when read in and out of the datastore:
24
- # default is string, but you can also specify :integer, :float, :set, :array, :datetime, and :serialized.
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 (one of :integer, :float, :set, :array, :datetime, or :serialized)
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) }
@@ -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::Adapter.read(self.table_name, ids, options)
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::Adapter.read(self.table_name, id, options)
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/Integer/Float] range_key of the object to find
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::Adapter.query(self.table_name, options.merge({hash_value: hash_key})).collect do |item|
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