dynamoid 0.6.1 → 0.7.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.
Files changed (92) hide show
  1. data/.travis.yml +4 -0
  2. data/Gemfile +3 -2
  3. data/Gemfile.lock +40 -45
  4. data/README.markdown +55 -25
  5. data/Rakefile +31 -0
  6. data/VERSION +1 -1
  7. data/doc/Dynamoid.html +58 -42
  8. data/doc/Dynamoid/Adapter.html +666 -179
  9. data/doc/Dynamoid/Adapter/AwsSdk.html +752 -236
  10. data/doc/Dynamoid/Associations.html +28 -21
  11. data/doc/Dynamoid/Associations/Association.html +102 -49
  12. data/doc/Dynamoid/Associations/BelongsTo.html +28 -25
  13. data/doc/Dynamoid/Associations/ClassMethods.html +95 -52
  14. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +28 -25
  15. data/doc/Dynamoid/Associations/HasMany.html +28 -25
  16. data/doc/Dynamoid/Associations/HasOne.html +28 -25
  17. data/doc/Dynamoid/Associations/ManyAssociation.html +138 -94
  18. data/doc/Dynamoid/Associations/SingleAssociation.html +67 -38
  19. data/doc/Dynamoid/Components.html +60 -22
  20. data/doc/Dynamoid/Config.html +61 -44
  21. data/doc/Dynamoid/Config/Options.html +90 -61
  22. data/doc/Dynamoid/Criteria.html +28 -21
  23. data/doc/Dynamoid/Criteria/Chain.html +508 -100
  24. data/doc/Dynamoid/Criteria/ClassMethods.html +26 -19
  25. data/doc/Dynamoid/Dirty.html +424 -0
  26. data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
  27. data/doc/Dynamoid/Document.html +451 -84
  28. data/doc/Dynamoid/Document/ClassMethods.html +281 -102
  29. data/doc/Dynamoid/Errors.html +29 -22
  30. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
  31. data/doc/Dynamoid/Errors/DocumentNotValid.html +36 -25
  32. data/doc/Dynamoid/Errors/Error.html +27 -20
  33. data/doc/Dynamoid/Errors/InvalidField.html +27 -19
  34. data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
  35. data/doc/Dynamoid/Errors/MissingRangeKey.html +27 -19
  36. data/doc/Dynamoid/Fields.html +94 -77
  37. data/doc/Dynamoid/Fields/ClassMethods.html +166 -37
  38. data/doc/Dynamoid/Finders.html +28 -21
  39. data/doc/Dynamoid/Finders/ClassMethods.html +505 -78
  40. data/doc/Dynamoid/IdentityMap.html +492 -0
  41. data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
  42. data/doc/Dynamoid/Indexes.html +41 -28
  43. data/doc/Dynamoid/Indexes/ClassMethods.html +45 -29
  44. data/doc/Dynamoid/Indexes/Index.html +100 -62
  45. data/doc/Dynamoid/Middleware.html +115 -0
  46. data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
  47. data/doc/Dynamoid/Persistence.html +326 -85
  48. data/doc/Dynamoid/Persistence/ClassMethods.html +275 -109
  49. data/doc/Dynamoid/Validations.html +47 -31
  50. data/doc/_index.html +116 -71
  51. data/doc/class_list.html +13 -7
  52. data/doc/css/full_list.css +4 -2
  53. data/doc/css/style.css +60 -44
  54. data/doc/file.LICENSE.html +26 -19
  55. data/doc/file.README.html +152 -48
  56. data/doc/file_list.html +14 -8
  57. data/doc/frames.html +20 -5
  58. data/doc/index.html +152 -48
  59. data/doc/js/app.js +52 -43
  60. data/doc/js/full_list.js +14 -9
  61. data/doc/js/jquery.js +4 -16
  62. data/doc/method_list.html +446 -540
  63. data/doc/top-level-namespace.html +27 -20
  64. data/{Dynamoid.gemspec → dynamoid.gemspec} +21 -8
  65. data/lib/dynamoid/adapter.rb +11 -10
  66. data/lib/dynamoid/adapter/aws_sdk.rb +40 -19
  67. data/lib/dynamoid/components.rb +2 -1
  68. data/lib/dynamoid/criteria/chain.rb +29 -11
  69. data/lib/dynamoid/dirty.rb +6 -0
  70. data/lib/dynamoid/document.rb +34 -19
  71. data/lib/dynamoid/fields.rb +36 -30
  72. data/lib/dynamoid/finders.rb +7 -5
  73. data/lib/dynamoid/persistence.rb +37 -10
  74. data/spec/app/models/address.rb +2 -0
  75. data/spec/app/models/camel_case.rb +10 -0
  76. data/spec/app/models/car.rb +6 -0
  77. data/spec/app/models/nuclear_submarine.rb +5 -0
  78. data/spec/app/models/subscription.rb +2 -2
  79. data/spec/app/models/vehicle.rb +7 -0
  80. data/spec/dynamoid/adapter/aws_sdk_spec.rb +20 -11
  81. data/spec/dynamoid/adapter_spec.rb +67 -82
  82. data/spec/dynamoid/associations/association_spec.rb +30 -30
  83. data/spec/dynamoid/criteria/chain_spec.rb +56 -9
  84. data/spec/dynamoid/criteria_spec.rb +3 -0
  85. data/spec/dynamoid/dirty_spec.rb +8 -0
  86. data/spec/dynamoid/document_spec.rb +109 -47
  87. data/spec/dynamoid/fields_spec.rb +32 -3
  88. data/spec/dynamoid/finders_spec.rb +12 -0
  89. data/spec/dynamoid/persistence_spec.rb +73 -8
  90. data/spec/spec_helper.rb +1 -0
  91. data/spec/support/with_partitioning.rb +15 -0
  92. metadata +22 -9
@@ -13,6 +13,12 @@ module Dynamoid
13
13
  clear_changes { super }
14
14
  end
15
15
 
16
+ def update!(*)
17
+ ret = super
18
+ clear_changes #update! completely reloads all fields on the class, so any extant changes are wiped out
19
+ ret
20
+ end
21
+
16
22
  def reload
17
23
  super.tap { clear_changes }
18
24
  end
@@ -8,9 +8,10 @@ module Dynamoid #:nodoc:
8
8
  include Dynamoid::Components
9
9
 
10
10
  included do
11
- class_attribute :options, :read_only_attributes
11
+ class_attribute :options, :read_only_attributes, :base_class
12
12
  self.options = {}
13
13
  self.read_only_attributes = []
14
+ self.base_class = self
14
15
 
15
16
  Dynamoid::Config.included_models << self
16
17
  end
@@ -28,6 +29,7 @@ module Dynamoid #:nodoc:
28
29
  # @since 0.4.0
29
30
  def table(options = {})
30
31
  self.options = options
32
+ super if defined? super
31
33
  end
32
34
 
33
35
  def attr_readonly(*read_only_attributes)
@@ -55,6 +57,13 @@ module Dynamoid #:nodoc:
55
57
  options[:key] || :id
56
58
  end
57
59
 
60
+ # Returns the number of items for this class.
61
+ #
62
+ # @since 0.6.1
63
+ def count
64
+ Dynamoid::Adapter::AwsSdk.count(table_name)
65
+ end
66
+
58
67
  # Initialize a new object and immediately save it to the database.
59
68
  #
60
69
  # @param [Hash] attrs Attributes with which to create the object.
@@ -63,7 +72,7 @@ module Dynamoid #:nodoc:
63
72
  #
64
73
  # @since 0.2.0
65
74
  def create(attrs = {})
66
- new(attrs).tap(&:save)
75
+ attrs[:type] ? attrs[:type].constantize.new(attrs).tap(&:save) : new(attrs).tap(&:save)
67
76
  end
68
77
 
69
78
  # Initialize a new object and immediately save it to the database. Raise an exception if persistence failed.
@@ -74,7 +83,7 @@ module Dynamoid #:nodoc:
74
83
  #
75
84
  # @since 0.2.0
76
85
  def create!(attrs = {})
77
- new(attrs).tap(&:save!)
86
+ attrs[:type] ? attrs[:type].constantize.new(attrs).tap(&:save!) : new(attrs).tap(&:save!)
78
87
  end
79
88
 
80
89
  # Initialize a new object.
@@ -85,18 +94,21 @@ module Dynamoid #:nodoc:
85
94
  #
86
95
  # @since 0.2.0
87
96
  def build(attrs = {})
88
- new(attrs)
97
+ attrs[:type] ? attrs[:type].constantize.new(attrs) : new(attrs)
89
98
  end
90
99
 
91
100
  # Does this object exist?
92
101
  #
93
- # @param [String] id the id of the object
102
+ # @param [Mixed] id_or_conditions the id of the object or a hash with the options to filter from.
94
103
  #
95
104
  # @return [Boolean] true/false
96
105
  #
97
106
  # @since 0.2.0
98
- def exists?(id)
99
- !! find(id)
107
+ def exists?(id_or_conditions = {})
108
+ case id_or_conditions
109
+ when Hash then ! where(id_or_conditions).all.empty?
110
+ else !! find(id_or_conditions)
111
+ end
100
112
  end
101
113
  end
102
114
 
@@ -109,8 +121,6 @@ module Dynamoid #:nodoc:
109
121
  # @since 0.2.0
110
122
  def initialize(attrs = {})
111
123
  run_callbacks :initialize do
112
- self.class.send(:field, self.class.hash_key) unless self.respond_to?(self.class.hash_key)
113
-
114
124
  @new_record = true
115
125
  @attributes ||= {}
116
126
  @associations ||= {}
@@ -131,18 +141,27 @@ module Dynamoid #:nodoc:
131
141
  super
132
142
  else
133
143
  return false if other.nil?
134
- other.respond_to?(:hash_key) && other.hash_key == self.hash_key
144
+ other.is_a?(Dynamoid::Document) && self.hash_key == other.hash_key && self.range_value == other.range_value
135
145
  end
136
146
  end
137
147
 
148
+ def eql?(other)
149
+ self == other
150
+ end
151
+
152
+ def hash
153
+ hash_key.hash ^ range_value.hash
154
+ end
155
+
138
156
  # Reload an object from the database -- if you suspect the object has changed in the datastore and you need those
139
- # changes to be reflected immediately, you would call this method.
157
+ # changes to be reflected immediately, you would call this method. This is a consistent read.
140
158
  #
141
159
  # @return [Dynamoid::Document] the document this method was called on
142
160
  #
143
161
  # @since 0.2.0
144
162
  def reload
145
- self.attributes = self.class.find(hash_key, :range_key => range_value).attributes
163
+ range_key_value = range_value ? dumped_range_value : nil
164
+ self.attributes = self.class.find(hash_key, :range_key => range_key_value, :consistent_read => true).attributes
146
165
  @associations.values.each(&:reset)
147
166
  self
148
167
  end
@@ -171,14 +190,10 @@ module Dynamoid #:nodoc:
171
190
  self.send("#{self.class.range_key}=", value)
172
191
  end
173
192
 
174
- def range_value
175
- if range_key = self.class.range_key
176
- self.send(range_key)
177
- end
178
- end
193
+ private
179
194
 
180
- def range_value=(value)
181
- self.send("#{self.class.range_key}=", value)
195
+ def dumped_range_value
196
+ dump_field(range_value, self.class.attributes[self.class.range_key])
182
197
  end
183
198
  end
184
199
  end
@@ -1,7 +1,7 @@
1
1
  # encoding: utf-8
2
2
  module Dynamoid #:nodoc:
3
3
 
4
- # All fields on a Dynamoid::Document must be explicitly defined -- if you have fields in the database that are not
4
+ # All fields on a Dynamoid::Document must be explicitly defined -- if you have fields in the database that are not
5
5
  # specified with field, then they will be ignored.
6
6
  module Fields
7
7
  extend ActiveSupport::Concern
@@ -14,11 +14,13 @@ module Dynamoid #:nodoc:
14
14
  self.attributes = {}
15
15
  field :created_at, :datetime
16
16
  field :updated_at, :datetime
17
+
18
+ field :id #Default primary key
17
19
  end
18
-
20
+
19
21
  module ClassMethods
20
-
21
- # Specify a field for a document. Its type determines how it is coerced when read in and out of the datastore:
22
+
23
+ # Specify a field for a document. Its type determines how it is coerced when read in and out of the datastore:
22
24
  # default is string, but you can also specify :integer, :float, :set, :array, :datetime, and :serialized.
23
25
  #
24
26
  # @param [Symbol] name the name of the field
@@ -28,7 +30,7 @@ module Dynamoid #:nodoc:
28
30
  # @since 0.2.0
29
31
  def field(name, type = :string, options = {})
30
32
  named = name.to_s
31
- self.attributes[name] = {:type => type}.merge(options)
33
+ self.attributes = attributes.merge(name => {:type => type}.merge(options))
32
34
 
33
35
  define_method(named) { read_attribute(named) }
34
36
  define_method("#{named}?") { !read_attribute(named).nil? }
@@ -39,8 +41,24 @@ module Dynamoid #:nodoc:
39
41
  field(name, type)
40
42
  self.range_key = name
41
43
  end
44
+
45
+ def table(options)
46
+ #a default 'id' column is created when Dynamoid::Document is included
47
+ unless(attributes.has_key? hash_key)
48
+ remove_field :id
49
+ field(hash_key)
50
+ end
51
+ end
52
+
53
+ def remove_field(field)
54
+ field = field.to_sym
55
+ attributes.delete(field) or raise "No such field"
56
+ remove_method field
57
+ remove_method :"#{field}="
58
+ remove_method :"#{field}?"
59
+ end
42
60
  end
43
-
61
+
44
62
  # You can access the attributes of an object directly on its attributes method, which is by default an empty hash.
45
63
  attr_accessor :attributes
46
64
  alias :raw_attributes :attributes
@@ -80,24 +98,8 @@ module Dynamoid #:nodoc:
80
98
  #
81
99
  # @since 0.2.0
82
100
  def update_attributes(attributes)
83
- attributes.each {|attribute, value| self.write_attribute(attribute, value)}
84
- if self.new_record # if never saved save.
85
- save
86
- else # update attributes if we have saved.
87
- # next if self.read_only_attributes.include? attribute.to_s put this back in.
88
- run_callbacks(:save) do
89
- update! do |u|
90
- attributes.each do |attribute, value|
91
- u.set attribute => dump_field(
92
- self.read_attribute(attribute),
93
- self.class.attributes[attribute.to_sym]
94
- )
95
- end
96
- end
97
- end
98
-
99
- save
100
- end
101
+ attributes.each {|attribute, value| self.write_attribute(attribute, value)} unless attributes.nil? || attributes.empty?
102
+ save
101
103
  end
102
104
 
103
105
  # Update a single attribute, saving the object afterwards.
@@ -110,9 +112,9 @@ module Dynamoid #:nodoc:
110
112
  write_attribute(attribute, value)
111
113
  save
112
114
  end
113
-
115
+
114
116
  private
115
-
117
+
116
118
  # Automatically called during the created callback to set the created_at time.
117
119
  #
118
120
  # @since 0.2.0
@@ -122,11 +124,15 @@ module Dynamoid #:nodoc:
122
124
 
123
125
  # Automatically called during the save callback to set the updated_at time.
124
126
  #
125
- # @since 0.2.0
127
+ # @since 0.2.0
126
128
  def set_updated_at
127
129
  self.updated_at = DateTime.now
128
130
  end
129
-
131
+
132
+ def set_type
133
+ self.type ||= self.class.to_s if self.class.attributes[:type]
134
+ end
135
+
130
136
  end
131
-
132
- end
137
+
138
+ end
@@ -31,19 +31,21 @@ module Dynamoid
31
31
  end
32
32
  end
33
33
 
34
- # Find all object by hash key or hash and range key
34
+ # Return objects found by the given array of ids, either hash keys, or hash/range key combinations using BatchGet.
35
+ # Returns empty array if no results found.
35
36
  #
36
37
  # @param [Array<ID>] ids
38
+ # @param [Hash] options: Passed to the underlying query.
37
39
  #
38
40
  # @example
39
41
  # find all the user with hash key
40
42
  # User.find_all(['1', '2', '3'])
41
43
  #
42
- # find all the tweets using hash key and range key
43
- # Tweet.find_all([['1', 'red'], ['1', 'green'])
44
- def find_all(ids)
44
+ # find all the tweets using hash key and range key with consistent read
45
+ # Tweet.find_all([['1', 'red'], ['1', 'green']], :consistent_read => true)
46
+ def find_all(ids, options = {})
45
47
  items = Dynamoid::Adapter.read(self.table_name, ids, options)
46
- items[self.table_name].collect{|i| from_database(i) }
48
+ items ? items[self.table_name].map{|i| from_database(i)} : []
47
49
  end
48
50
 
49
51
  # Find one object directly by id.
@@ -13,11 +13,8 @@ module Dynamoid
13
13
 
14
14
  module ClassMethods
15
15
 
16
- # Returns the name of the table the class is for.
17
- #
18
- # @since 0.2.0
19
16
  def table_name
20
- "#{Dynamoid::Config.namespace}_#{options[:name] ? options[:name] : self.name.split('::').last.downcase.pluralize}"
17
+ @table_name ||= "#{Dynamoid::Config.namespace}_#{options[:name] || base_class.name.split('::').last.downcase.pluralize}"
21
18
  end
22
19
 
23
20
  # Creates a table.
@@ -57,7 +54,8 @@ module Dynamoid
57
54
  end
58
55
 
59
56
  def from_database(attrs = {})
60
- new(attrs).tap { |r| r.new_record = false }
57
+ clazz = attrs[:type] ? obj = attrs[:type].constantize : self
58
+ clazz.new(attrs).tap { |r| r.new_record = false }
61
59
  end
62
60
 
63
61
  # Undump an object into a hash, converting each type from a string representation of itself into the type specified by the field.
@@ -170,10 +168,24 @@ module Dynamoid
170
168
  self
171
169
  end
172
170
 
171
+ #
172
+ # update!() will increment the lock_version if the table has the column, but will not check it. Thus, a concurrent save will
173
+ # never cause an update! to fail, but an update! may cause a concurrent save to fail.
174
+ #
175
+ #
173
176
  def update!(conditions = {}, &block)
174
- options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
175
- new_attrs = Dynamoid::Adapter.update_item(self.class.table_name, self.hash_key, options.merge(:conditions => conditions), &block)
176
- load(new_attrs)
177
+ run_callbacks(:update) do
178
+ options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
179
+ new_attrs = Dynamoid::Adapter.update_item(self.class.table_name, self.hash_key, options.merge(:conditions => conditions)) do |t|
180
+ if(self.class.attributes[:lock_version])
181
+ raise "Optimistic locking cannot be used with Partitioning" if(Dynamoid::Config.partitioning)
182
+ t.add(lock_version: 1)
183
+ end
184
+
185
+ yield t
186
+ end
187
+ load(new_attrs)
188
+ end
177
189
  end
178
190
 
179
191
  def update(conditions = {}, &block)
@@ -245,7 +257,7 @@ module Dynamoid
245
257
  raise ArgumentError, "Unknown type #{options[:type]}"
246
258
  end
247
259
  end
248
-
260
+
249
261
  # Persist the object into the datastore. Assign it an id first if it doesn't have one; then afterwards,
250
262
  # save its indexes.
251
263
  #
@@ -253,13 +265,28 @@ module Dynamoid
253
265
  def persist(conditions = nil)
254
266
  run_callbacks(:save) do
255
267
  self.hash_key = SecureRandom.uuid if self.hash_key.nil? || self.hash_key.blank?
268
+
269
+ # Add an exists check to prevent overwriting existing records with new ones
270
+ if(new_record?)
271
+ conditions ||= {}
272
+ (conditions[:unless_exists] ||= []) << self.class.hash_key
273
+ end
274
+
275
+ # Add an optimistic locking check if the lock_version column exists
276
+ if(self.class.attributes[:lock_version])
277
+ conditions ||= {}
278
+ raise "Optimistic locking cannot be used with Partitioning" if(Dynamoid::Config.partitioning)
279
+ self.lock_version = (lock_version || 0) + 1
280
+ #Uses the original lock_version value from ActiveModel::Dirty in case user changed lock_version manually
281
+ (conditions[:if] ||= {})[:lock_version] = changes[:lock_version][0] if(changes[:lock_version][0])
282
+ end
283
+
256
284
  Dynamoid::Adapter.write(self.class.table_name, self.dump, conditions)
257
285
  save_indexes
258
286
  @new_record = false
259
287
  true
260
288
  end
261
289
  end
262
-
263
290
  end
264
291
 
265
292
  end
@@ -4,6 +4,8 @@ class Address
4
4
  field :city
5
5
  field :options, :serialized
6
6
  field :deliverable, :boolean
7
+
8
+ field :lock_version, :integer #Provides Optimistic Locking
7
9
 
8
10
  def zip_code=(zip_code)
9
11
  self.city = "Chicago"
@@ -10,6 +10,8 @@ class CamelCase
10
10
 
11
11
  before_create :doing_before_create
12
12
  after_create :doing_after_create
13
+ before_update :doing_before_update
14
+ after_update :doing_after_update
13
15
 
14
16
  private
15
17
 
@@ -21,4 +23,12 @@ class CamelCase
21
23
  true
22
24
  end
23
25
 
26
+ def doing_before_update
27
+ true
28
+ end
29
+
30
+ def doing_after_update
31
+ true
32
+ end
33
+
24
34
  end
@@ -0,0 +1,6 @@
1
+ require_relative 'vehicle'
2
+
3
+ class Car < Vehicle
4
+
5
+ field :power_locks, :boolean
6
+ end
@@ -0,0 +1,5 @@
1
+ require_relative 'vehicle'
2
+ class NuclearSubmarine < Vehicle
3
+
4
+ field :torpedoes, :integer
5
+ end
@@ -1,8 +1,8 @@
1
1
  class Subscription
2
2
  include Dynamoid::Document
3
-
3
+
4
4
  field :length, :integer
5
-
5
+
6
6
  belongs_to :magazine
7
7
  has_and_belongs_to_many :users
8
8
 
@@ -0,0 +1,7 @@
1
+ class Vehicle
2
+ include Dynamoid::Document
3
+
4
+ field :type
5
+
6
+ field :description
7
+ end
@@ -50,23 +50,27 @@ describe Dynamoid::Adapter::AwsSdk do
50
50
  end
51
51
 
52
52
  it 'performs query on a table with a range and selects items in a range' do
53
- Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
53
+ Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
54
+ end
55
+
56
+ it 'performs query on a table with a range and selects items in a range with :select option' do
57
+ Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_value => 0.0..3.0, :select => :all).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
54
58
  end
55
59
 
56
60
  it 'performs query on a table with a range and selects items greater than' do
57
- Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_greater_than => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(3)}]
61
+ Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_greater_than => 1.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(3)}]
58
62
  end
59
63
 
60
64
  it 'performs query on a table with a range and selects items less than' do
61
- Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_less_than => 2.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}]
65
+ Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_less_than => 2.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}]
62
66
  end
63
67
 
64
68
  it 'performs query on a table with a range and selects items gte' do
65
- Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_gte => 1.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
69
+ Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_gte => 1.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
66
70
  end
67
71
 
68
72
  it 'performs query on a table with a range and selects items lte' do
69
- Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_lte => 3.0).should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
73
+ Dynamoid::Adapter.query(test_table3, :hash_value => '1', :range_lte => 3.0).to_a.should =~ [{:id => '1', :range => BigDecimal.new(1)}, {:id => '1', :range => BigDecimal.new(3)}]
70
74
  end
71
75
  end
72
76
 
@@ -85,7 +89,7 @@ describe Dynamoid::Adapter::AwsSdk do
85
89
  end
86
90
 
87
91
  it 'performs query on a table with a range and selects items less than that is in the correct order, scan_index_forward true' do
88
- query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => true)
92
+ query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => true).to_a
89
93
  query[0].should == {:id => '1', :order => 1, :range => BigDecimal.new(1)}
90
94
  query[1].should == {:id => '1', :order => 2, :range => BigDecimal.new(2)}
91
95
  query[2].should == {:id => '1', :order => 3, :range => BigDecimal.new(3)}
@@ -95,7 +99,7 @@ describe Dynamoid::Adapter::AwsSdk do
95
99
  end
96
100
 
97
101
  it 'performs query on a table with a range and selects items less than that is in the correct order, scan_index_forward false' do
98
- query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => false)
102
+ query = Dynamoid::Adapter.query(test_table4, :hash_value => '1', :range_greater_than => 0, :scan_index_forward => false).to_a
99
103
  query[5].should == {:id => '1', :order => 1, :range => BigDecimal.new(1)}
100
104
  query[4].should == {:id => '1', :order => 2, :range => BigDecimal.new(2)}
101
105
  query[3].should == {:id => '1', :order => 3, :range => BigDecimal.new(3)}
@@ -157,6 +161,11 @@ describe Dynamoid::Adapter::AwsSdk do
157
161
  end
158
162
 
159
163
  # BatchGetItem
164
+ it 'passes options to underlying BatchGet call' do
165
+ AWS::DynamoDB::BatchGet.any_instance.expects(:table).with(test_table1, :all, ['1', '2'], :consistent_read => true)
166
+ described_class.batch_get_item({test_table1 => ['1', '2']}, :consistent_read => true)
167
+ end
168
+
160
169
  it "performs BatchGetItem with singular keys" do
161
170
  Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
162
171
  Dynamoid::Adapter.put_item(test_table2, {:id => '1', :name => 'Justin'})
@@ -259,14 +268,14 @@ describe Dynamoid::Adapter::AwsSdk do
259
268
  it 'performs query on a table and returns items' do
260
269
  Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
261
270
 
262
- Dynamoid::Adapter.query(test_table1, :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
271
+ Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
263
272
  end
264
273
 
265
274
  it 'performs query on a table and returns items if there are multiple items' do
266
275
  Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
267
276
  Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
268
277
 
269
- Dynamoid::Adapter.query(test_table1, :hash_value => '1').should == { :id=> '1', :name=>"Josh" }
278
+ Dynamoid::Adapter.query(test_table1, :hash_value => '1').first.should == { :id=> '1', :name=>"Josh" }
270
279
  end
271
280
 
272
281
  it_behaves_like 'range queries'
@@ -275,14 +284,14 @@ describe Dynamoid::Adapter::AwsSdk do
275
284
  it 'performs scan on a table and returns items' do
276
285
  Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
277
286
 
278
- Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
287
+ Dynamoid::Adapter.scan(test_table1, :name => 'Josh').to_a.should == [{ :id=> '1', :name=>"Josh" }]
279
288
  end
280
289
 
281
290
  it 'performs scan on a table and returns items if there are multiple items but only one match' do
282
291
  Dynamoid::Adapter.put_item(test_table1, {:id => '1', :name => 'Josh'})
283
292
  Dynamoid::Adapter.put_item(test_table1, {:id => '2', :name => 'Justin'})
284
293
 
285
- Dynamoid::Adapter.scan(test_table1, :name => 'Josh').should == [{ :id=> '1', :name=>"Josh" }]
294
+ Dynamoid::Adapter.scan(test_table1, :name => 'Josh').to_a.should == [{ :id=> '1', :name=>"Josh" }]
286
295
  end
287
296
 
288
297
  it 'performs scan on a table and returns multiple items if there are multiple matches' do