dynamoid-moda 0.7.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.
Files changed (136) hide show
  1. checksums.yaml +15 -0
  2. data/.document +5 -0
  3. data/.rspec +1 -0
  4. data/.travis.yml +7 -0
  5. data/Gemfile +24 -0
  6. data/Gemfile.lock +118 -0
  7. data/Gemfile_activemodel4 +24 -0
  8. data/Gemfile_activemodel4.lock +88 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.markdown +360 -0
  11. data/Rakefile +93 -0
  12. data/VERSION +1 -0
  13. data/doc/.nojekyll +0 -0
  14. data/doc/Dynamoid.html +328 -0
  15. data/doc/Dynamoid/Adapter.html +1872 -0
  16. data/doc/Dynamoid/Adapter/AwsSdk.html +2101 -0
  17. data/doc/Dynamoid/Adapter/Local.html +1574 -0
  18. data/doc/Dynamoid/Associations.html +138 -0
  19. data/doc/Dynamoid/Associations/Association.html +847 -0
  20. data/doc/Dynamoid/Associations/BelongsTo.html +161 -0
  21. data/doc/Dynamoid/Associations/ClassMethods.html +766 -0
  22. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +167 -0
  23. data/doc/Dynamoid/Associations/HasMany.html +167 -0
  24. data/doc/Dynamoid/Associations/HasOne.html +161 -0
  25. data/doc/Dynamoid/Associations/ManyAssociation.html +1684 -0
  26. data/doc/Dynamoid/Associations/SingleAssociation.html +627 -0
  27. data/doc/Dynamoid/Components.html +242 -0
  28. data/doc/Dynamoid/Config.html +412 -0
  29. data/doc/Dynamoid/Config/Options.html +638 -0
  30. data/doc/Dynamoid/Criteria.html +138 -0
  31. data/doc/Dynamoid/Criteria/Chain.html +1471 -0
  32. data/doc/Dynamoid/Criteria/ClassMethods.html +105 -0
  33. data/doc/Dynamoid/Dirty.html +424 -0
  34. data/doc/Dynamoid/Dirty/ClassMethods.html +174 -0
  35. data/doc/Dynamoid/Document.html +1033 -0
  36. data/doc/Dynamoid/Document/ClassMethods.html +1116 -0
  37. data/doc/Dynamoid/Errors.html +125 -0
  38. data/doc/Dynamoid/Errors/ConditionalCheckFailedException.html +141 -0
  39. data/doc/Dynamoid/Errors/DocumentNotValid.html +221 -0
  40. data/doc/Dynamoid/Errors/Error.html +137 -0
  41. data/doc/Dynamoid/Errors/InvalidField.html +141 -0
  42. data/doc/Dynamoid/Errors/InvalidQuery.html +131 -0
  43. data/doc/Dynamoid/Errors/MissingRangeKey.html +141 -0
  44. data/doc/Dynamoid/Fields.html +686 -0
  45. data/doc/Dynamoid/Fields/ClassMethods.html +438 -0
  46. data/doc/Dynamoid/Finders.html +135 -0
  47. data/doc/Dynamoid/Finders/ClassMethods.html +943 -0
  48. data/doc/Dynamoid/IdentityMap.html +492 -0
  49. data/doc/Dynamoid/IdentityMap/ClassMethods.html +534 -0
  50. data/doc/Dynamoid/Indexes.html +321 -0
  51. data/doc/Dynamoid/Indexes/ClassMethods.html +369 -0
  52. data/doc/Dynamoid/Indexes/Index.html +1142 -0
  53. data/doc/Dynamoid/Middleware.html +115 -0
  54. data/doc/Dynamoid/Middleware/IdentityMap.html +264 -0
  55. data/doc/Dynamoid/Persistence.html +892 -0
  56. data/doc/Dynamoid/Persistence/ClassMethods.html +836 -0
  57. data/doc/Dynamoid/Validations.html +415 -0
  58. data/doc/_index.html +506 -0
  59. data/doc/class_list.html +53 -0
  60. data/doc/css/common.css +1 -0
  61. data/doc/css/full_list.css +57 -0
  62. data/doc/css/style.css +338 -0
  63. data/doc/file.LICENSE.html +73 -0
  64. data/doc/file.README.html +416 -0
  65. data/doc/file_list.html +58 -0
  66. data/doc/frames.html +28 -0
  67. data/doc/index.html +416 -0
  68. data/doc/js/app.js +214 -0
  69. data/doc/js/full_list.js +178 -0
  70. data/doc/js/jquery.js +4 -0
  71. data/doc/method_list.html +1144 -0
  72. data/doc/top-level-namespace.html +112 -0
  73. data/dynamoid-moda.gemspec +210 -0
  74. data/dynamoid.gemspec +208 -0
  75. data/lib/dynamoid.rb +46 -0
  76. data/lib/dynamoid/adapter.rb +267 -0
  77. data/lib/dynamoid/adapter/aws_sdk.rb +309 -0
  78. data/lib/dynamoid/associations.rb +106 -0
  79. data/lib/dynamoid/associations/association.rb +105 -0
  80. data/lib/dynamoid/associations/belongs_to.rb +44 -0
  81. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +40 -0
  82. data/lib/dynamoid/associations/has_many.rb +39 -0
  83. data/lib/dynamoid/associations/has_one.rb +39 -0
  84. data/lib/dynamoid/associations/many_association.rb +191 -0
  85. data/lib/dynamoid/associations/single_association.rb +69 -0
  86. data/lib/dynamoid/components.rb +37 -0
  87. data/lib/dynamoid/config.rb +57 -0
  88. data/lib/dynamoid/config/options.rb +78 -0
  89. data/lib/dynamoid/criteria.rb +29 -0
  90. data/lib/dynamoid/criteria/chain.rb +326 -0
  91. data/lib/dynamoid/dirty.rb +47 -0
  92. data/lib/dynamoid/document.rb +199 -0
  93. data/lib/dynamoid/errors.rb +28 -0
  94. data/lib/dynamoid/fields.rb +138 -0
  95. data/lib/dynamoid/finders.rb +133 -0
  96. data/lib/dynamoid/identity_map.rb +96 -0
  97. data/lib/dynamoid/indexes.rb +69 -0
  98. data/lib/dynamoid/indexes/index.rb +103 -0
  99. data/lib/dynamoid/middleware/identity_map.rb +16 -0
  100. data/lib/dynamoid/persistence.rb +292 -0
  101. data/lib/dynamoid/validations.rb +36 -0
  102. data/spec/app/models/address.rb +13 -0
  103. data/spec/app/models/camel_case.rb +34 -0
  104. data/spec/app/models/car.rb +6 -0
  105. data/spec/app/models/magazine.rb +11 -0
  106. data/spec/app/models/message.rb +9 -0
  107. data/spec/app/models/nuclear_submarine.rb +5 -0
  108. data/spec/app/models/sponsor.rb +8 -0
  109. data/spec/app/models/subscription.rb +12 -0
  110. data/spec/app/models/tweet.rb +12 -0
  111. data/spec/app/models/user.rb +26 -0
  112. data/spec/app/models/vehicle.rb +7 -0
  113. data/spec/dynamoid/adapter/aws_sdk_spec.rb +376 -0
  114. data/spec/dynamoid/adapter_spec.rb +155 -0
  115. data/spec/dynamoid/associations/association_spec.rb +194 -0
  116. data/spec/dynamoid/associations/belongs_to_spec.rb +71 -0
  117. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +47 -0
  118. data/spec/dynamoid/associations/has_many_spec.rb +42 -0
  119. data/spec/dynamoid/associations/has_one_spec.rb +45 -0
  120. data/spec/dynamoid/associations_spec.rb +16 -0
  121. data/spec/dynamoid/config_spec.rb +27 -0
  122. data/spec/dynamoid/criteria/chain_spec.rb +210 -0
  123. data/spec/dynamoid/criteria_spec.rb +75 -0
  124. data/spec/dynamoid/dirty_spec.rb +57 -0
  125. data/spec/dynamoid/document_spec.rb +180 -0
  126. data/spec/dynamoid/fields_spec.rb +156 -0
  127. data/spec/dynamoid/finders_spec.rb +147 -0
  128. data/spec/dynamoid/identity_map_spec.rb +45 -0
  129. data/spec/dynamoid/indexes/index_spec.rb +104 -0
  130. data/spec/dynamoid/indexes_spec.rb +25 -0
  131. data/spec/dynamoid/persistence_spec.rb +301 -0
  132. data/spec/dynamoid/validations_spec.rb +36 -0
  133. data/spec/dynamoid_spec.rb +14 -0
  134. data/spec/spec_helper.rb +55 -0
  135. data/spec/support/with_partitioning.rb +15 -0
  136. metadata +363 -0
@@ -0,0 +1,42 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Dynamoid::Associations::HasMany" do
4
+
5
+ before do
6
+ @magazine = Magazine.create
7
+ @user = User.create
8
+ @camel_case = CamelCase.create
9
+ end
10
+
11
+ it 'determines equality from its records' do
12
+ @subscription = @magazine.subscriptions.create
13
+
14
+ @magazine.subscriptions.should == @subscription
15
+ end
16
+
17
+ it 'determines target association correctly' do
18
+ @magazine.subscriptions.send(:target_association).should == :magazine
19
+ @user.books.send(:target_association).should == :owner
20
+ @camel_case.users.send(:target_association).should == :camel_case
21
+ end
22
+
23
+ it 'determins target class correctly' do
24
+ @magazine.subscriptions.send(:target_class).should == Subscription
25
+ @user.books.send(:target_class).should == Magazine
26
+ end
27
+
28
+ it 'determines target attribute' do
29
+ @magazine.subscriptions.send(:target_attribute).should == :magazine_ids
30
+ @user.books.send(:target_attribute).should == :owner_ids
31
+ end
32
+
33
+ it 'associates belongs_to automatically' do
34
+ @subscription = @magazine.subscriptions.create
35
+
36
+ @subscription.magazine.should == @magazine
37
+
38
+ @magazine = @user.books.create
39
+ @magazine.owner.should == @user
40
+ end
41
+
42
+ end
@@ -0,0 +1,45 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Dynamoid::Associations::HasOne" do
4
+
5
+ before do
6
+ @magazine = Magazine.create
7
+ @user = User.create
8
+ @camel_case = CamelCase.create
9
+ end
10
+
11
+ it 'determines nil if it has no associated record' do
12
+ @magazine.sponsor.should be_nil
13
+ end
14
+
15
+ it 'determines target association correctly' do
16
+ @camel_case.sponsor.send(:target_association).should == :camel_case
17
+ end
18
+
19
+ it 'returns only one object when associated' do
20
+ @magazine.sponsor.create
21
+
22
+ @magazine.sponsor.should_not be_a_kind_of Array
23
+ end
24
+
25
+ it 'delegates equality to its source record' do
26
+ @sponsor = @magazine.sponsor.create
27
+
28
+ @magazine.sponsor.should == @sponsor
29
+ end
30
+
31
+ it 'is equal from its target record' do
32
+ @sponsor = @magazine.sponsor.create
33
+
34
+ @magazine.sponsor.should == @sponsor
35
+ end
36
+
37
+ it 'associates belongs_to automatically' do
38
+ @sponsor = @magazine.sponsor.create
39
+ @sponsor.magazine.should == @magazine
40
+ @magazine.sponsor.should == @sponsor
41
+
42
+ @subscription = @user.monthly.create
43
+ @subscription.customer.should == @user
44
+ end
45
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Dynamoid::Associations" do
4
+
5
+ before do
6
+ @magazine = Magazine.create
7
+ end
8
+
9
+ it 'defines a getter' do
10
+ @magazine.should respond_to :subscriptions
11
+ end
12
+
13
+ it 'defines a setter' do
14
+ @magazine.should respond_to :subscriptions=
15
+ end
16
+ end
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Dynamoid::Config" do
4
+
5
+ before(:each) do
6
+ Dynamoid::Config.reset_namespace
7
+ end
8
+
9
+ after(:each) do
10
+ Dynamoid.config {|config| config.namespace = 'dynamoid_tests'}
11
+ end
12
+
13
+ it 'returns a namespace for non-Rails apps' do
14
+ Dynamoid::Config.namespace.should == 'dynamoid'
15
+ end
16
+
17
+ it 'returns a namespace for Rails apps' do
18
+ class Rails; end
19
+ Rails.stubs(:application => stubs(:class => stubs(:parent_name => 'TestApp')))
20
+ Rails.stubs(:env => 'development')
21
+ Dynamoid::Config.send(:option, :namespace, :default => defined?(Rails) ? "dynamoid_#{Rails.application.class.parent_name}_#{Rails.env}" : "dynamoid")
22
+
23
+ # TODO Make this return what we actually expect
24
+ Dynamoid::Config.namespace.should == "dynamoid_Mocha_development"
25
+ end
26
+
27
+ end
@@ -0,0 +1,210 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe "Dynamoid::Associations::Chain" do
4
+
5
+ before(:each) do
6
+ @time = DateTime.now
7
+ @user = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com', :password => 'Test123')
8
+ @chain = Dynamoid::Criteria::Chain.new(User)
9
+ end
10
+
11
+ it 'finds matching index for a query' do
12
+ @chain.query = {:name => 'Josh'}
13
+ @chain.send(:index).should == User.indexes[[:name]]
14
+
15
+ @chain.query = {:email => 'josh@joshsymonds.com'}
16
+ @chain.send(:index).should == User.indexes[[:email]]
17
+
18
+ @chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
19
+ @chain.send(:index).should == User.indexes[[:email, :name]]
20
+ end
21
+
22
+ it 'makes string symbol for query keys' do
23
+ @chain.query = {'name' => 'Josh'}
24
+ @chain.send(:index).should == User.indexes[[:name]]
25
+ end
26
+
27
+ it 'finds matching index for a range query' do
28
+ @chain.query = {"created_at.gt" => @time - 1.day}
29
+ @chain.send(:index).should == User.indexes[[:created_at]]
30
+
31
+ @chain.query = {:name => 'Josh', "created_at.lt" => @time - 1.day}
32
+ @chain.send(:index).should == User.indexes[[:created_at, :name]]
33
+ end
34
+
35
+ it 'does not find an index if there is not an appropriate one' do
36
+ @chain.query = {:password => 'Test123'}
37
+ @chain.send(:index).should be_nil
38
+
39
+ @chain.query = {:password => 'Test123', :created_at => @time}
40
+ @chain.send(:index).should be_nil
41
+ end
42
+
43
+ it 'returns values for index for a query' do
44
+ @chain.query = {:name => 'Josh'}
45
+ @chain.send(:index_query).should == {:hash_value => 'Josh'}
46
+
47
+ @chain.query = {:email => 'josh@joshsymonds.com'}
48
+ @chain.send(:index_query).should == {:hash_value => 'josh@joshsymonds.com'}
49
+
50
+ @chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
51
+ @chain.send(:index_query).should == {:hash_value => 'josh@joshsymonds.com.Josh'}
52
+
53
+ @chain.query = {:name => 'Josh', 'created_at.gt' => @time}
54
+ @chain.send(:index_query).should == {:hash_value => 'Josh', :range_greater_than => @time.to_f}
55
+ end
56
+
57
+ it 'finds records with an index' do
58
+ @chain.query = {:name => 'Josh'}
59
+ @chain.send(:records_with_index).should == @user
60
+
61
+ @chain.query = {:email => 'josh@joshsymonds.com'}
62
+ @chain.send(:records_with_index).should == @user
63
+
64
+ @chain.query = {:name => 'Josh', :email => 'josh@joshsymonds.com'}
65
+ @chain.send(:records_with_index).should == @user
66
+ end
67
+
68
+ it 'returns records with an index for a ranged query' do
69
+ @chain.query = {:name => 'Josh', "created_at.gt" => @time - 1.day}
70
+ @chain.send(:records_with_index).should == @user
71
+
72
+ @chain.query = {:name => 'Josh', "created_at.lt" => @time + 1.day}
73
+ @chain.send(:records_with_index).should == @user
74
+ end
75
+
76
+ it 'finds records without an index' do
77
+ @chain.query = {:password => 'Test123'}
78
+ @chain.send(:records_without_index).to_a.should == [@user]
79
+ end
80
+
81
+ it "doesn't crash if it finds a nil id in the index" do
82
+ @chain.query = {:name => 'Josh', "created_at.gt" => @time - 1.day}
83
+ Dynamoid::Adapter.expects(:query).
84
+ with("dynamoid_tests_index_user_created_ats_and_names", kind_of(Hash)).
85
+ returns([{ids: nil}, {ids: Set.new([42])}])
86
+ @chain.send(:ids_from_index).should == Set.new([42])
87
+ end
88
+
89
+ it 'defines each' do
90
+ @chain.query = {:name => 'Josh'}
91
+ @chain.each {|u| u.update_attribute(:name, 'Justin')}
92
+
93
+ User.find(@user.id).name.should == 'Justin'
94
+ end
95
+
96
+ it 'includes Enumerable' do
97
+ @chain.query = {:name => 'Josh'}
98
+
99
+ @chain.collect {|u| u.name}.should == ['Josh']
100
+ end
101
+
102
+ it 'uses a range query when only a hash key or range key is specified in query' do
103
+ # Primary key is [hash_key].
104
+ @chain = Dynamoid::Criteria::Chain.new(Address)
105
+ @chain.query = {}
106
+ @chain.send(:range?).should be_false
107
+
108
+ @chain = Dynamoid::Criteria::Chain.new(Address)
109
+ @chain.query = { :id => 'test' }
110
+ @chain.send(:range?).should be_true
111
+
112
+ @chain = Dynamoid::Criteria::Chain.new(Address)
113
+ @chain.query = { :id => 'test', :city => 'Bucharest' }
114
+ @chain.send(:range?).should be_false
115
+
116
+ # Primary key is [hash_key, range_key].
117
+ @chain = Dynamoid::Criteria::Chain.new(Tweet)
118
+ @chain.query = { }
119
+ @chain.send(:range?).should be_false
120
+
121
+ @chain = Dynamoid::Criteria::Chain.new(Tweet)
122
+ @chain.query = { :tweet_id => 'test' }
123
+ @chain.send(:range?).should be_true
124
+
125
+ @chain.query = {:tweet_id => 'test', :msg => 'hai'}
126
+ @chain.send(:range?).should be_false
127
+
128
+ @chain.query = {:tweet_id => 'test', :group => 'xx'}
129
+ @chain.send(:range?).should be_true
130
+
131
+ @chain.query = {:tweet_id => 'test', :group => 'xx', :msg => 'hai'}
132
+ @chain.send(:range?).should be_false
133
+
134
+ @chain.query = { :group => 'xx' }
135
+ @chain.send(:range?).should be_false
136
+
137
+ @chain.query = { :group => 'xx', :msg => 'hai' }
138
+ @chain.send(:range?).should be_false
139
+ end
140
+
141
+ context 'range queries' do
142
+ before do
143
+ @tweet1 = Tweet.create(:tweet_id => "x", :group => "one")
144
+ @tweet2 = Tweet.create(:tweet_id => "x", :group => "two")
145
+ @tweet3 = Tweet.create(:tweet_id => "xx", :group => "two")
146
+ @chain = Dynamoid::Criteria::Chain.new(Tweet)
147
+ end
148
+
149
+ it 'finds tweets with a simple range query' do
150
+ @chain.query = { :tweet_id => "x" }
151
+ @chain.send(:records_with_range).to_a.size.should == 2
152
+ @chain.all.size.should == 2
153
+ @chain.limit(1).size.should == 1
154
+ end
155
+
156
+ it 'finds tweets with a start' do
157
+ @chain.query = { :tweet_id => "x" }
158
+ @chain.start(@tweet1)
159
+ @chain.all.should =~ [@tweet2]
160
+ end
161
+
162
+ it 'finds one specific tweet' do
163
+ @chain = Dynamoid::Criteria::Chain.new(Tweet)
164
+ @chain.query = { :tweet_id => "xx", :group => "two" }
165
+ @chain.send(:records_with_range).to_a.should == [@tweet3]
166
+ end
167
+ end
168
+
169
+ context 'destroy alls' do
170
+ before do
171
+ @tweet1 = Tweet.create(:tweet_id => "x", :group => "one")
172
+ @tweet2 = Tweet.create(:tweet_id => "x", :group => "two")
173
+ @tweet3 = Tweet.create(:tweet_id => "xx", :group => "two")
174
+ @chain = Dynamoid::Criteria::Chain.new(Tweet)
175
+ end
176
+
177
+ it 'destroys tweet with a range simple range query' do
178
+ @chain.query = { :tweet_id => "x" }
179
+ @chain.all.size.should == 2
180
+ @chain.destroy_all
181
+ @chain.consistent.all.size.should == 0
182
+ end
183
+
184
+ it 'deletes one specific tweet with range' do
185
+ @chain = Dynamoid::Criteria::Chain.new(Tweet)
186
+ @chain.query = { :tweet_id => "xx", :group => "two" }
187
+ @chain.all.size.should == 1
188
+ @chain.destroy_all
189
+ @chain.consistent.all.size.should == 0
190
+ end
191
+ end
192
+
193
+ context 'batch queries' do
194
+ before do
195
+ @tweets = (1..4).map{|count| Tweet.create(:tweet_id => count.to_s, :group => (count % 2).to_s)}
196
+ @chain = Dynamoid::Criteria::Chain.new(Tweet)
197
+ end
198
+
199
+ it 'returns all results' do
200
+ @chain.batch(2).all.to_a.size.should == @tweets.size
201
+ end
202
+
203
+ it 'throws exception if partitioning is used with batching' do
204
+ previous_value = Dynamoid::Config.partitioning
205
+ Dynamoid::Config.partitioning = true
206
+ expect { @chain.batch(2) }.to raise_error
207
+ Dynamoid::Config.partitioning = previous_value
208
+ end
209
+ end
210
+ end
@@ -0,0 +1,75 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe "Dynamoid::Criteria" do
4
+ before(:all) do
5
+ Magazine.create_table
6
+ end
7
+
8
+ before do
9
+ @user1 = User.create(:name => 'Josh', :email => 'josh@joshsymonds.com')
10
+ @user2 = User.create(:name => 'Justin', :email => 'justin@joshsymonds.com')
11
+ end
12
+
13
+ it 'finds first using where' do
14
+ User.where(:name => 'Josh').first.should == @user1
15
+ end
16
+
17
+ it 'finds all using where' do
18
+ User.where(:name => 'Josh').all.should == [@user1]
19
+ end
20
+
21
+ it 'returns all records' do
22
+ User.all.should =~ [@user1, @user2]
23
+ User.all.first.new_record.should be_false
24
+ end
25
+
26
+ it 'returns empty attributes for where' do
27
+ Magazine.where(:name => 'Josh').all.should == []
28
+ end
29
+
30
+ it 'returns empty attributes for all' do
31
+ Magazine.all.should == []
32
+ end
33
+
34
+ it 'passes each to all members' do
35
+ User.each do |u|
36
+ u.id.should == @user1.id || @user2.id
37
+ u.new_record.should be_false
38
+ end
39
+ end
40
+
41
+ it 'returns n records' do
42
+ User.limit(1).size.should eq(1)
43
+ 5.times { |i| User.create(:name => 'Josh', :email => 'josh_#{i}@joshsymonds.com') }
44
+ User.where(:name => 'Josh').all.size.should == 6
45
+ User.where(:name => 'Josh').limit(2).size.should == 2
46
+ end
47
+
48
+ # TODO This test is broken using the AWS SDK adapter.
49
+ #it 'start with a record' do
50
+ # 5.times { |i| User.create(:name => 'Josh', :email => 'josh_#{i}@joshsymonds.com') }
51
+ # all = User.all
52
+ # User.start(all[3]).all.should eq(all[4..-1])
53
+ #
54
+ # all = User.where(:name => 'Josh').all
55
+ # User.where(:name => 'Josh').start(all[3]).all.should eq(all[4..-1])
56
+ #end
57
+
58
+ it 'send consistent option to adapter' do
59
+ Dynamoid::Adapter.expects(:get_item).with { |table_name, key, options| options[:consistent_read] == true }
60
+ User.where(:name => 'x').consistent.first
61
+
62
+ Dynamoid::Adapter.expects(:query).with { |table_name, options| options[:consistent_read] == true }.returns([])
63
+ Tweet.where(:tweet_id => 'xx', :group => 'two').consistent.all
64
+
65
+ Dynamoid::Adapter.expects(:query).with { |table_name, options| options[:consistent_read] == false }.returns([])
66
+ Tweet.where(:tweet_id => 'xx', :group => 'two').all
67
+ end
68
+
69
+ it 'raises exception when consistent_read is used with scan' do
70
+ expect do
71
+ User.where(:password => 'password').consistent.first
72
+ end.to raise_error(Dynamoid::Errors::InvalidQuery)
73
+ end
74
+
75
+ end
@@ -0,0 +1,57 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe 'Dynamoid::Dirty' do
4
+
5
+ context 'changes' do
6
+ it 'should be empty' do
7
+ tweet = Tweet.new
8
+ tweet.msg_changed?.should be_false
9
+ end
10
+
11
+ it 'should not be empty' do
12
+ tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
13
+ tweet.changed?.should be_true
14
+ tweet.group_was.should be_nil
15
+ end
16
+
17
+ it 'should be empty when loaded from database' do
18
+ Tweet.create!(:tweet_id => "1", :group => 'abc')
19
+ tweet = Tweet.where(:tweet_id => "1", :group => 'abc').first
20
+ tweet.changed?.should be_false
21
+ tweet.group = 'abc'
22
+ tweet.reload
23
+ tweet.changed?.should be_false
24
+ end
25
+
26
+ it 'should be empty after an update' do
27
+ tweet = Tweet.create!(:tweet_id => "1", :group => 'abc')
28
+ tweet.update! do |t|
29
+ t.set(msg: "foo")
30
+ end
31
+ tweet.changed?.should be_false
32
+ end
33
+
34
+ it 'track changes after saves' do
35
+ tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
36
+ tweet.save!
37
+ tweet.changed?.should be_false
38
+
39
+ tweet.user_name = 'xyz'
40
+ tweet.user_name_changed?.should be_true
41
+ tweet.user_name_was.should be_nil
42
+ tweet.save!
43
+
44
+ tweet.user_name_changed?.should be_false
45
+ tweet.user_name = 'abc'
46
+ tweet.user_name_was.should == 'xyz'
47
+ end
48
+
49
+ it 'clear changes on save' do
50
+ tweet = Tweet.new(:tweet_id => "1", :group => 'abc')
51
+ tweet.group = 'xyz'
52
+ tweet.group_changed?.should be_true
53
+ tweet.save!
54
+ tweet.group_changed?.should be_false
55
+ end
56
+ end
57
+ end