danielharan-mongo_mapper 0.6.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +53 -0
  4. data/Rakefile +55 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/lib/mongo_mapper.rb +134 -0
  8. data/lib/mongo_mapper/associations.rb +183 -0
  9. data/lib/mongo_mapper/associations/base.rb +110 -0
  10. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  11. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +22 -0
  12. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +25 -0
  13. data/lib/mongo_mapper/associations/many_documents_proxy.rb +127 -0
  14. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +53 -0
  16. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongo_mapper/associations/many_proxy.rb +6 -0
  18. data/lib/mongo_mapper/associations/proxy.rb +80 -0
  19. data/lib/mongo_mapper/callbacks.rb +109 -0
  20. data/lib/mongo_mapper/dirty.rb +136 -0
  21. data/lib/mongo_mapper/document.rb +481 -0
  22. data/lib/mongo_mapper/dynamic_finder.rb +35 -0
  23. data/lib/mongo_mapper/embedded_document.rb +386 -0
  24. data/lib/mongo_mapper/finder_options.rb +133 -0
  25. data/lib/mongo_mapper/key.rb +36 -0
  26. data/lib/mongo_mapper/observing.rb +50 -0
  27. data/lib/mongo_mapper/pagination.rb +53 -0
  28. data/lib/mongo_mapper/rails_compatibility/document.rb +15 -0
  29. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +27 -0
  30. data/lib/mongo_mapper/serialization.rb +54 -0
  31. data/lib/mongo_mapper/serializers/json_serializer.rb +92 -0
  32. data/lib/mongo_mapper/support.rb +193 -0
  33. data/lib/mongo_mapper/validations.rb +41 -0
  34. data/mongo_mapper.gemspec +171 -0
  35. data/specs.watchr +32 -0
  36. data/test/NOTE_ON_TESTING +1 -0
  37. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +55 -0
  38. data/test/functional/associations/test_belongs_to_proxy.rb +48 -0
  39. data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
  40. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +156 -0
  41. data/test/functional/associations/test_many_embedded_proxy.rb +196 -0
  42. data/test/functional/associations/test_many_polymorphic_proxy.rb +339 -0
  43. data/test/functional/associations/test_many_proxy.rb +384 -0
  44. data/test/functional/test_associations.rb +44 -0
  45. data/test/functional/test_binary.rb +18 -0
  46. data/test/functional/test_callbacks.rb +85 -0
  47. data/test/functional/test_dirty.rb +159 -0
  48. data/test/functional/test_document.rb +1180 -0
  49. data/test/functional/test_embedded_document.rb +125 -0
  50. data/test/functional/test_logger.rb +20 -0
  51. data/test/functional/test_pagination.rb +95 -0
  52. data/test/functional/test_rails_compatibility.rb +25 -0
  53. data/test/functional/test_string_id_compatibility.rb +72 -0
  54. data/test/functional/test_validations.rb +369 -0
  55. data/test/models.rb +271 -0
  56. data/test/support/custom_matchers.rb +55 -0
  57. data/test/support/timing.rb +16 -0
  58. data/test/test_helper.rb +27 -0
  59. data/test/unit/serializers/test_json_serializer.rb +189 -0
  60. data/test/unit/test_association_base.rb +166 -0
  61. data/test/unit/test_document.rb +204 -0
  62. data/test/unit/test_dynamic_finder.rb +125 -0
  63. data/test/unit/test_embedded_document.rb +718 -0
  64. data/test/unit/test_finder_options.rb +296 -0
  65. data/test/unit/test_key.rb +172 -0
  66. data/test/unit/test_mongo_mapper.rb +65 -0
  67. data/test/unit/test_observing.rb +101 -0
  68. data/test/unit/test_pagination.rb +113 -0
  69. data/test/unit/test_rails_compatibility.rb +49 -0
  70. data/test/unit/test_serializations.rb +52 -0
  71. data/test/unit/test_support.rb +342 -0
  72. data/test/unit/test_time_zones.rb +40 -0
  73. data/test/unit/test_validations.rb +503 -0
  74. metadata +233 -0
@@ -0,0 +1,159 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class DirtyTest < Test::Unit::TestCase
5
+ def setup
6
+ @document = Class.new do
7
+ include MongoMapper::Document
8
+ set_collection_name 'test'
9
+ key :phrase, String
10
+ end
11
+ @document.collection.remove
12
+
13
+ Status.collection.remove
14
+ Project.collection.remove
15
+ end
16
+
17
+ context "marking changes" do
18
+ should "not happen if there are none" do
19
+ doc = @document.new
20
+ doc.phrase_changed?.should be_false
21
+ doc.phrase_change.should be_nil
22
+ end
23
+
24
+ should "happen when change happens" do
25
+ doc = @document.new
26
+ doc.phrase = 'Golly Gee Willikers Batman'
27
+ doc.phrase_changed?.should be_true
28
+ doc.phrase_was.should be_nil
29
+ doc.phrase_change.should == [nil, 'Golly Gee Willikers Batman']
30
+ end
31
+
32
+ should "happen when initializing" do
33
+ doc = @document.new(:phrase => 'Foo')
34
+ doc.changed?.should be_true
35
+ end
36
+
37
+ should "clear changes on save" do
38
+ doc = @document.new
39
+ doc.phrase = 'Golly Gee Willikers Batman'
40
+ doc.phrase_changed?.should be_true
41
+ doc.save
42
+ doc.phrase_changed?.should_not be_true
43
+ doc.phrase_change.should be_nil
44
+ end
45
+
46
+ should "clear changes on save!" do
47
+ doc = @document.new
48
+ doc.phrase = 'Golly Gee Willikers Batman'
49
+ doc.phrase_changed?.should be_true
50
+ doc.save!
51
+ doc.phrase_changed?.should_not be_true
52
+ doc.phrase_change.should be_nil
53
+ end
54
+
55
+ should "not happen when loading from database" do
56
+ doc = @document.create(:phrase => 'Foo')
57
+
58
+ doc = doc.reload
59
+ doc.changed?.should be_false
60
+ end
61
+
62
+ should "happen if changed after loading from database" do
63
+ doc = @document.create(:phrase => 'Foo')
64
+
65
+ doc = doc.reload
66
+ doc.changed?.should be_false
67
+ doc.phrase = 'Bar'
68
+ doc.changed?.should be_true
69
+ end
70
+ end
71
+
72
+ context "blank new value and type integer" do
73
+ should "not mark changes" do
74
+ @document.key :age, Integer
75
+
76
+ [nil, ''].each do |value|
77
+ doc = @document.new
78
+ doc.age = value
79
+ doc.age_changed?.should be_false
80
+ doc.age_change.should be_nil
81
+ end
82
+ end
83
+ end
84
+
85
+ context "blank new value and type float" do
86
+ should "not mark changes" do
87
+ @document.key :amount, Float
88
+
89
+ [nil, ''].each do |value|
90
+ doc = @document.new
91
+ doc.amount = value
92
+ doc.amount_changed?.should be_false
93
+ doc.amount_change.should be_nil
94
+ end
95
+ end
96
+ end
97
+
98
+ context "changed?" do
99
+ should "be true if key changed" do
100
+ doc = @document.new
101
+ doc.phrase = 'A penny saved is a penny earned.'
102
+ doc.changed?.should be_true
103
+ end
104
+
105
+ should "be false if no keys changed" do
106
+ @document.new.changed?.should be_false
107
+ end
108
+ end
109
+
110
+ context "changes" do
111
+ should "be empty hash if no changes" do
112
+ @document.new.changes.should == {}
113
+ end
114
+
115
+ should "be hash of keys with values of changes if there are changes" do
116
+ doc = @document.new
117
+ doc.phrase = 'A penny saved is a penny earned.'
118
+ doc.changes.should == {'phrase' => [nil, 'A penny saved is a penny earned.']}
119
+ end
120
+ end
121
+
122
+ context "changed" do
123
+ should "be empty array if no changes" do
124
+ @document.new.changed.should == []
125
+ end
126
+
127
+ should "be array of keys that have changed if there are changes" do
128
+ doc = @document.new
129
+ doc.phrase = 'A penny saved is a penny earned.'
130
+ doc.changed.should == ['phrase']
131
+ end
132
+ end
133
+
134
+ context "will_change!" do
135
+ should "mark changes" do
136
+ doc = @document.create(:phrase => 'Foo')
137
+
138
+ doc.phrase << 'bar'
139
+ doc.phrase_changed?.should be_false
140
+
141
+ doc.phrase_will_change!
142
+ doc.phrase_changed?.should be_true
143
+ doc.phrase_change.should == ['Foobar', 'Foobar']
144
+
145
+ doc.phrase << '!'
146
+ doc.phrase_changed?.should be_true
147
+ doc.phrase_change.should == ['Foobar', 'Foobar!']
148
+ end
149
+ end
150
+
151
+ context "changing a foreign key through association" do
152
+ should "mark changes" do
153
+ status = Status.create(:name => 'Foo')
154
+ status.project = Project.create(:name => 'Bar')
155
+ status.changed?.should be_true
156
+ status.changed.should == %w(project_id)
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,1180 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class DocumentTest < Test::Unit::TestCase
5
+ def setup
6
+ @document = Class.new do
7
+ include MongoMapper::Document
8
+ set_collection_name 'users'
9
+
10
+ key :first_name, String
11
+ key :last_name, String
12
+ key :age, Integer
13
+ key :date, Date
14
+ end
15
+ @document.collection.remove
16
+ end
17
+
18
+ context "Saving a document with a custom id" do
19
+ should "clear custom id flag when saved" do
20
+ @document.key :_id, String
21
+ doc = @document.new(:id => '1234')
22
+ doc.using_custom_id?.should be_true
23
+ doc.save.should be_true
24
+ doc.using_custom_id?.should be_false
25
+ end
26
+ end
27
+
28
+ context "Saving a document with a blank binary value" do
29
+ setup do
30
+ @document.key :file, Binary
31
+ end
32
+
33
+ should "not fail" do
34
+ doc = @document.new(:file => nil)
35
+ doc.save
36
+ end
37
+ end
38
+
39
+ context "Loading a document from the database with keys that are not defined" do
40
+ setup do
41
+ @id = Mongo::ObjectID.new
42
+ @document.collection.insert({
43
+ :_id => @id,
44
+ :first_name => 'John',
45
+ :last_name => 'Nunemaker',
46
+ :age => 27,
47
+ :favorite_color => 'red',
48
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
49
+ })
50
+ end
51
+
52
+ should "assign all keys from database" do
53
+ doc = @document.find(@id)
54
+ doc.first_name.should == 'John'
55
+ doc.last_name.should == 'Nunemaker'
56
+ doc.age.should == 27
57
+ doc.favorite_color.should == 'red'
58
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
59
+ end
60
+ end
61
+
62
+ context "Document Class Methods" do
63
+ context "Using key with type Array" do
64
+ setup do
65
+ @document.key :tags, Array
66
+ end
67
+
68
+ should "give correct default" do
69
+ doc = @document.new
70
+ doc.tags.should == []
71
+ end
72
+
73
+ should "work with assignment" do
74
+ doc = @document.new
75
+ doc.tags = %w(foo bar)
76
+ doc.tags.should == %w(foo bar)
77
+ end
78
+
79
+ should "work with assignment after saving" do
80
+ doc = @document.new
81
+ doc.tags = %w(foo bar)
82
+ doc.save
83
+ doc.tags.should == %w(foo bar)
84
+ doc.reload.tags.should == %w(foo bar)
85
+ end
86
+
87
+ should "work with assignment then <<" do
88
+ doc = @document.new
89
+ doc.tags = []
90
+ doc.tags << "foo"
91
+ doc.tags.should == ["foo"]
92
+ end
93
+
94
+ should "work with <<" do
95
+ doc = @document.new
96
+ doc.tags << "foo"
97
+ doc.tags.should == ["foo"]
98
+ end
99
+
100
+ should "work with << then save" do
101
+ doc = @document.new
102
+ doc.tags << "foo"
103
+ doc.tags << "bar"
104
+ doc.save
105
+ doc.tags.should == %w(foo bar)
106
+ doc.reload.tags.should == %w(foo bar)
107
+ end
108
+ end
109
+
110
+ context "Using key with type Hash" do
111
+ setup do
112
+ @document.key :foo, Hash
113
+ end
114
+
115
+ should "give correct default" do
116
+ doc = @document.new
117
+ doc.foo.should == {}
118
+ end
119
+
120
+ should "work with []=" do
121
+ doc = @document.new
122
+ doc.foo["quux"] = "bar"
123
+ doc.foo["quux"].should == "bar"
124
+ doc.foo.should == { "quux" => "bar" }
125
+ end
126
+
127
+ should "work with indifferent access" do
128
+ doc = @document.new
129
+ doc.foo = {:baz => 'bar'}
130
+ doc.foo[:baz].should == 'bar'
131
+ doc.foo['baz'].should == 'bar'
132
+ end
133
+
134
+ should "work with indifferent access after save" do
135
+ doc = @document.new
136
+ doc.foo = {:baz => 'bar'}
137
+ doc.save
138
+
139
+ doc = doc.reload
140
+ doc.foo[:baz].should == 'bar'
141
+ doc.foo['baz'].should == 'bar'
142
+ end
143
+ end
144
+
145
+ context "Using key with custom type with default" do
146
+ setup do
147
+ @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
148
+ end
149
+
150
+ should "default to default" do
151
+ doc = @document.new
152
+ doc.window.should == WindowSize.new(600, 480)
153
+
154
+ end
155
+
156
+ should "save and load from mongo" do
157
+ doc = @document.new
158
+ doc.save
159
+
160
+ doc = doc.reload
161
+ doc.window.should == WindowSize.new(600, 480)
162
+ end
163
+ end
164
+
165
+ context "Creating a single document" do
166
+ setup do
167
+ @doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
168
+ end
169
+
170
+ should "create a document in correct collection" do
171
+ @document.count.should == 1
172
+ end
173
+
174
+ should "automatically set id" do
175
+ @doc_instance.id.should be_instance_of(Mongo::ObjectID)
176
+ @doc_instance._id.should be_instance_of(Mongo::ObjectID)
177
+ end
178
+
179
+ should "no longer be new?" do
180
+ @doc_instance.new?.should be_false
181
+ end
182
+
183
+ should "return instance of document" do
184
+ @doc_instance.should be_instance_of(@document)
185
+ @doc_instance.first_name.should == 'John'
186
+ @doc_instance.last_name.should == 'Nunemaker'
187
+ @doc_instance.age.should == 27
188
+ end
189
+ end
190
+
191
+ context "Creating a document with no attributes provided" do
192
+ setup do
193
+ @document = Class.new do
194
+ include MongoMapper::Document
195
+ set_collection_name 'test'
196
+ end
197
+ @document.collection.remove
198
+ end
199
+
200
+ should "create the document" do
201
+ lambda {
202
+ @document.create
203
+ }.should change { @document.count }.by(1)
204
+ end
205
+ end
206
+
207
+ context "Creating multiple documents" do
208
+ setup do
209
+ @doc_instances = @document.create([
210
+ {:first_name => 'John', :last_name => 'Nunemaker', :age => '27'},
211
+ {:first_name => 'Steve', :last_name => 'Smith', :age => '28'},
212
+ ])
213
+ end
214
+
215
+ should "create multiple documents" do
216
+ @document.count.should == 2
217
+ end
218
+
219
+ should "return an array of doc instances" do
220
+ @doc_instances.map do |doc_instance|
221
+ doc_instance.should be_instance_of(@document)
222
+ end
223
+ end
224
+ end
225
+
226
+ context "Updating a document" do
227
+ setup do
228
+ doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
229
+ @doc_instance = @document.update(doc._id, {:age => 40})
230
+ end
231
+
232
+ should "update attributes provided" do
233
+ @doc_instance.age.should == 40
234
+ end
235
+
236
+ should "not update existing attributes that were not set to update" do
237
+ @doc_instance.first_name.should == 'John'
238
+ @doc_instance.last_name.should == 'Nunemaker'
239
+ end
240
+
241
+ should "not create new document" do
242
+ @document.count.should == 1
243
+ end
244
+ end
245
+
246
+ should "raise error when updating single doc if not provided id and attributes" do
247
+ doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
248
+ lambda { @document.update }.should raise_error(ArgumentError)
249
+ lambda { @document.update(doc._id) }.should raise_error(ArgumentError)
250
+ lambda { @document.update(doc._id, [1]) }.should raise_error(ArgumentError)
251
+ end
252
+
253
+ context "Updating multiple documents" do
254
+ setup do
255
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
256
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
257
+
258
+ @doc_instances = @document.update({
259
+ @doc1._id => {:age => 30},
260
+ @doc2._id => {:age => 30},
261
+ })
262
+ end
263
+
264
+ should "not create any new documents" do
265
+ @document.count.should == 2
266
+ end
267
+
268
+ should "should return an array of doc instances" do
269
+ @doc_instances.map do |doc_instance|
270
+ doc_instance.should be_instance_of(@document)
271
+ end
272
+ end
273
+
274
+ should "update the documents" do
275
+ @document.find(@doc1._id).age.should == 30
276
+ @document.find(@doc2._id).age.should == 30
277
+ end
278
+ end
279
+
280
+ should "raise error when updating multiple documents if not a hash" do
281
+ lambda { @document.update([1, 2]) }.should raise_error(ArgumentError)
282
+ end
283
+
284
+ context "Finding documents" do
285
+ setup do
286
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
287
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
288
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
289
+ end
290
+
291
+ should "return nil if nothing provided for find" do
292
+ @document.find.should be_nil
293
+ end
294
+
295
+ should "raise document not found if nothing provided for find!" do
296
+ lambda { @document.find! }.should raise_error(MongoMapper::DocumentNotFound)
297
+ end
298
+
299
+ context "with a single id" do
300
+ should "work" do
301
+ @document.find(@doc1._id).should == @doc1
302
+ end
303
+
304
+ should "return nil if document not found with find" do
305
+ @document.find(123).should be_nil
306
+ end
307
+
308
+ should "raise error if document not found with find!" do
309
+ lambda {
310
+ @document.find!(123)
311
+ }.should raise_error(MongoMapper::DocumentNotFound)
312
+ end
313
+ end
314
+
315
+ context "with multiple id's" do
316
+ should "work as arguments" do
317
+ @document.find(@doc1._id, @doc2._id).should == [@doc1, @doc2]
318
+ end
319
+
320
+ should "work as array" do
321
+ @document.find([@doc1._id, @doc2._id]).should == [@doc1, @doc2]
322
+ end
323
+
324
+ should "return array if array only has one element" do
325
+ @document.find([@doc1._id]).should == [@doc1]
326
+ end
327
+ end
328
+
329
+ should "be able to find using condition auto-detection" do
330
+ @document.first(:first_name => 'John').should == @doc1
331
+ @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
332
+ end
333
+
334
+ context "with :all" do
335
+ should "find all documents" do
336
+ @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
337
+ end
338
+
339
+ should "be able to add conditions" do
340
+ @document.find(:all, :first_name => 'John').should == [@doc1]
341
+ end
342
+ end
343
+
344
+ context "with #all" do
345
+ should "find all documents based on criteria" do
346
+ @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
347
+ @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
348
+ end
349
+ end
350
+
351
+ context "with :first" do
352
+ should "find first document" do
353
+ @document.find(:first, :order => 'first_name').should == @doc1
354
+ end
355
+ end
356
+
357
+ context "with #first" do
358
+ should "find first document based on criteria" do
359
+ @document.first(:order => 'first_name').should == @doc1
360
+ @document.first(:age => 28).should == @doc2
361
+ end
362
+ end
363
+
364
+ context "with :last" do
365
+ should "find last document" do
366
+ @document.find(:last, :order => 'age').should == @doc2
367
+ end
368
+ end
369
+
370
+ context "with #last" do
371
+ should "find last document based on criteria" do
372
+ @document.last(:order => 'age').should == @doc2
373
+ @document.last(:order => 'age', :age => 28).should == @doc2
374
+ end
375
+
376
+ should "raise error if no order provided" do
377
+ lambda { @document.last() }.should raise_error
378
+ end
379
+ end
380
+
381
+ context "with :find_by" do
382
+ should "find document based on argument" do
383
+ @document.find_by_first_name('John').should == @doc1
384
+ @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
385
+ @document.find_by_age(27).should == @doc1
386
+ end
387
+
388
+ should "not raise error" do
389
+ @document.find_by_first_name('Mongo').should be_nil
390
+ end
391
+
392
+ should "define a method for each key" do
393
+ @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
394
+ end
395
+ end
396
+
397
+ context "with dynamic finders" do
398
+ should "find document based on all arguments" do
399
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
400
+ end
401
+
402
+ should "not find the document if an argument is wrong" do
403
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
404
+ end
405
+
406
+ should "find all documents based on arguments" do
407
+ docs = @document.find_all_by_last_name('Nunemaker')
408
+ docs.should be_kind_of(Array)
409
+ docs.should include(@doc1)
410
+ docs.should include(@doc3)
411
+ end
412
+
413
+ should "initialize document with given arguments" do
414
+ doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
415
+ doc.should be_new
416
+ doc.first_name.should == 'David'
417
+ end
418
+
419
+ should "not initialize document if document is found" do
420
+ doc = @document.find_or_initialize_by_first_name('John')
421
+ doc.should_not be_new
422
+ end
423
+
424
+ should "create document with given arguments" do
425
+ doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
426
+ doc.should_not be_new
427
+ doc.first_name.should == 'David'
428
+ end
429
+
430
+ should "raise error if document is not found when using !" do
431
+ lambda {
432
+ @document.find_by_first_name_and_last_name!(1,2)
433
+ }.should raise_error(MongoMapper::DocumentNotFound)
434
+ end
435
+ end
436
+ end # finding documents
437
+
438
+ context "Finding document by id" do
439
+ setup do
440
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
441
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
442
+ end
443
+
444
+ should "be able to find by id" do
445
+ @document.find_by_id(@doc1._id).should == @doc1
446
+ @document.find_by_id(@doc2._id).should == @doc2
447
+ end
448
+
449
+ should "return nil if document not found" do
450
+ @document.find_by_id(1234).should be(nil)
451
+ end
452
+ end
453
+
454
+ context "Deleting a document" do
455
+ setup do
456
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
457
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
458
+ @document.delete(@doc1._id)
459
+ end
460
+
461
+ should "remove document from collection" do
462
+ @document.count.should == 1
463
+ end
464
+
465
+ should "not remove other documents" do
466
+ @document.find(@doc2._id).should_not be(nil)
467
+ end
468
+ end
469
+
470
+ context "Deleting multiple documents" do
471
+ should "work with multiple arguments" do
472
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
473
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
474
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
475
+ @document.delete(@doc1._id, @doc2._id)
476
+
477
+ @document.count.should == 1
478
+ end
479
+
480
+ should "work with array as argument" do
481
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
482
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
483
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
484
+ @document.delete([@doc1._id, @doc2._id])
485
+
486
+ @document.count.should == 1
487
+ end
488
+ end
489
+
490
+ context "Deleting all documents" do
491
+ setup do
492
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
493
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
494
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
495
+ end
496
+
497
+ should "remove all documents when given no conditions" do
498
+ @document.delete_all
499
+ @document.count.should == 0
500
+ end
501
+
502
+ should "only remove matching documents when given conditions" do
503
+ @document.delete_all({:first_name => 'John'})
504
+ @document.count.should == 2
505
+ end
506
+
507
+ should "convert the conditions to mongo criteria" do
508
+ @document.delete_all(:age => [26, 27])
509
+ @document.count.should == 1
510
+ end
511
+ end
512
+
513
+ context "Destroying a document" do
514
+ setup do
515
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
516
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
517
+ @document.destroy(@doc1._id)
518
+ end
519
+
520
+ should "remove document from collection" do
521
+ @document.count.should == 1
522
+ end
523
+
524
+ should "not remove other documents" do
525
+ @document.find(@doc2._id).should_not be(nil)
526
+ end
527
+ end
528
+
529
+ context "Destroying multiple documents" do
530
+ should "work with multiple arguments" do
531
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
532
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
533
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
534
+ @document.destroy(@doc1._id, @doc2._id)
535
+
536
+ @document.count.should == 1
537
+ end
538
+
539
+ should "work with array as argument" do
540
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
541
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
542
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
543
+ @document.destroy([@doc1._id, @doc2._id])
544
+
545
+ @document.count.should == 1
546
+ end
547
+ end
548
+
549
+ context "Destroying all documents" do
550
+ setup do
551
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
552
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
553
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
554
+ end
555
+
556
+ should "remove all documents when given no conditions" do
557
+ @document.destroy_all
558
+ @document.count.should == 0
559
+ end
560
+
561
+ should "only remove matching documents when given conditions" do
562
+ @document.destroy_all(:first_name => 'John')
563
+ @document.count.should == 2
564
+ @document.destroy_all(:age => 26)
565
+ @document.count.should == 1
566
+ end
567
+
568
+ should "convert the conditions to mongo criteria" do
569
+ @document.destroy_all(:age => [26, 27])
570
+ @document.count.should == 1
571
+ end
572
+ end
573
+
574
+ context ":dependent" do
575
+ setup do
576
+ # FIXME: make use of already defined models
577
+ class ::Property
578
+ include MongoMapper::Document
579
+ end
580
+ Property.collection.remove
581
+
582
+ class ::Thing
583
+ include MongoMapper::Document
584
+ key :name, String
585
+ end
586
+ Thing.collection.remove
587
+ end
588
+
589
+ teardown do
590
+ Object.send :remove_const, 'Property' if defined?(::Property)
591
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
592
+ end
593
+
594
+ context "many" do
595
+ context "=> destroy" do
596
+ setup do
597
+ Property.key :thing_id, ObjectId
598
+ Property.belongs_to :thing, :dependent => :destroy
599
+ Thing.many :properties, :dependent => :destroy
600
+
601
+ @thing = Thing.create(:name => "Tree")
602
+ @property1 = Property.create
603
+ @property2 = Property.create
604
+ @property3 = Property.create
605
+ @thing.properties << @property1
606
+ @thing.properties << @property2
607
+ @thing.properties << @property3
608
+ end
609
+
610
+ should "should destroy the associated documents" do
611
+ @thing.properties.count.should == 3
612
+ @thing.destroy
613
+ @thing.properties.count.should == 0
614
+ Property.count.should == 0
615
+ end
616
+ end
617
+
618
+ context "=> delete_all" do
619
+ setup do
620
+ Property.key :thing_id, ObjectId
621
+ Property.belongs_to :thing
622
+ Thing.has_many :properties, :dependent => :delete_all
623
+
624
+ @thing = Thing.create(:name => "Tree")
625
+ @property1 = Property.create
626
+ @property2 = Property.create
627
+ @property3 = Property.create
628
+ @thing.properties << @property1
629
+ @thing.properties << @property2
630
+ @thing.properties << @property3
631
+ end
632
+
633
+ should "should delete associated documents" do
634
+ @thing.properties.count.should == 3
635
+ @thing.destroy
636
+ @thing.properties.count.should == 0
637
+ Property.count.should == 0
638
+ end
639
+ end
640
+
641
+ context "=> nullify" do
642
+ setup do
643
+ Property.key :thing_id, ObjectId
644
+ Property.belongs_to :thing
645
+ Thing.has_many :properties, :dependent => :nullify
646
+
647
+ @thing = Thing.create(:name => "Tree")
648
+ @property1 = Property.create
649
+ @property2 = Property.create
650
+ @property3 = Property.create
651
+ @thing.properties << @property1
652
+ @thing.properties << @property2
653
+ @thing.properties << @property3
654
+ end
655
+
656
+ should "should nullify relationship but not destroy associated documents" do
657
+ @thing.properties.count.should == 3
658
+ @thing.destroy
659
+ @thing.properties.count.should == 0
660
+ Property.count.should == 3
661
+ end
662
+ end
663
+ end
664
+
665
+ context "belongs_to" do
666
+ context "=> destroy" do
667
+ setup do
668
+ Property.key :thing_id, ObjectId
669
+ Property.belongs_to :thing, :dependent => :destroy
670
+ Thing.has_many :properties
671
+
672
+ @thing = Thing.create(:name => "Tree")
673
+ @property1 = Property.create
674
+ @property2 = Property.create
675
+ @property3 = Property.create
676
+ @thing.properties << @property1
677
+ @thing.properties << @property2
678
+ @thing.properties << @property3
679
+ end
680
+
681
+ should "not execute on a belongs_to association" do
682
+ Thing.count.should == 1
683
+ @property1.destroy
684
+ Thing.count.should == 1
685
+ @property1.should be_frozen
686
+ end
687
+ end
688
+ end
689
+ end
690
+
691
+ context "Counting documents in collection" do
692
+ setup do
693
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
694
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
695
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
696
+ end
697
+
698
+ should "count all with no arguments" do
699
+ @document.count.should == 3
700
+ end
701
+
702
+ should "return 0 if there are no documents in the collection" do
703
+ @document.delete_all
704
+ @document.count.should == 0
705
+ end
706
+
707
+ should "return 0 if the collection does not exist" do
708
+ klass = Class.new do
709
+ include MongoMapper::Document
710
+ set_collection_name 'foobarbazwickdoesnotexist'
711
+ end
712
+ @document.collection.remove
713
+
714
+ klass.count.should == 0
715
+ end
716
+
717
+ should "return count for matching documents if conditions provided" do
718
+ @document.count(:age => 27).should == 1
719
+ end
720
+
721
+ should "convert the conditions to mongo criteria" do
722
+ @document.count(:age => [26, 27]).should == 2
723
+ end
724
+ end
725
+
726
+ context "Indexing" do
727
+ setup do
728
+ @document.collection.drop_indexes
729
+ end
730
+
731
+ should "allow creating index for a key" do
732
+ @document.ensure_index :first_name
733
+ MongoMapper.ensure_indexes!
734
+
735
+ @document.should have_index('first_name_1')
736
+ end
737
+
738
+ should "allow creating unique index for a key" do
739
+ @document.ensure_index :first_name, :unique => true
740
+ MongoMapper.ensure_indexes!
741
+
742
+ @document.should have_index('first_name_1')
743
+ end
744
+
745
+ should "allow creating index on multiple keys" do
746
+ @document.ensure_index [[:first_name, 1], [:last_name, -1]]
747
+ MongoMapper.ensure_indexes!
748
+
749
+ # order is different for different versions of ruby so instead of
750
+ # just checking have_index('first_name_1_last_name_-1') I'm checking
751
+ # the values of the indexes to make sure the index creation was successful
752
+ @document.collection.index_information.detect do |index|
753
+ keys = index[1]
754
+ keys.include?(['first_name', 1]) && keys.include?(['last_name', -1])
755
+ end.should_not be_nil
756
+ end
757
+
758
+ should "work with :index shortcut when defining key" do
759
+ @document.key :father, String, :index => true
760
+ MongoMapper.ensure_indexes!
761
+
762
+ @document.should have_index('father_1')
763
+ end
764
+ end
765
+ end # Document Class Methods
766
+
767
+ context "Saving a new document" do
768
+ setup do
769
+ @doc = @document.new(:first_name => 'John', :age => '27')
770
+ @doc.save
771
+ end
772
+
773
+ should "insert document into the collection" do
774
+ @document.count.should == 1
775
+ end
776
+
777
+ should "assign an id for the document" do
778
+ @doc.id.should be_instance_of(Mongo::ObjectID)
779
+ end
780
+
781
+ should "save attributes" do
782
+ @doc.first_name.should == 'John'
783
+ @doc.age.should == 27
784
+ end
785
+
786
+ should "update attributes in the database" do
787
+ doc = @doc.reload
788
+ doc.should == @doc
789
+ doc.first_name.should == 'John'
790
+ doc.age.should == 27
791
+ end
792
+
793
+ should "allow to add custom attributes to the document" do
794
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
795
+ @doc.save
796
+ doc = @doc.reload
797
+ doc.gender.should == 'male'
798
+ doc.tags.should == [1, "2"]
799
+ end
800
+
801
+ should "allow to use custom methods to assign properties" do
802
+ person = RealPerson.new(:realname => 'David')
803
+ person.save
804
+ person.reload.name.should == 'David'
805
+ end
806
+
807
+ context "with key of type date" do
808
+ should "save the date value as a Time object" do
809
+ doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
810
+ doc.save
811
+ doc.date.should == Date.new(2009, 12, 1)
812
+ end
813
+ end
814
+ end
815
+
816
+ context "Saving an existing document" do
817
+ setup do
818
+ @doc = @document.create(:first_name => 'John', :age => '27')
819
+ @doc.first_name = 'Johnny'
820
+ @doc.age = 30
821
+ @doc.save
822
+ end
823
+
824
+ should "not insert document into collection" do
825
+ @document.count.should == 1
826
+ end
827
+
828
+ should "update attributes" do
829
+ @doc.first_name.should == 'Johnny'
830
+ @doc.age.should == 30
831
+ end
832
+
833
+ should "update attributes in the database" do
834
+ doc = @doc.reload
835
+ doc.first_name.should == 'Johnny'
836
+ doc.age.should == 30
837
+ end
838
+
839
+ should "allow updating custom attributes" do
840
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
841
+ @doc.gender = 'Male'
842
+ @doc.save
843
+ @doc.reload.gender.should == 'Male'
844
+ end
845
+ end
846
+
847
+ context "Calling update attributes on a new document" do
848
+ setup do
849
+ @doc = @document.new(:first_name => 'John', :age => '27')
850
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
851
+ end
852
+
853
+ should "insert document into the collection" do
854
+ @document.count.should == 1
855
+ end
856
+
857
+ should "assign an id for the document" do
858
+ @doc.id.should be_instance_of(Mongo::ObjectID)
859
+ end
860
+
861
+ should "save attributes" do
862
+ @doc.first_name.should == 'Johnny'
863
+ @doc.age.should == 30
864
+ end
865
+
866
+ should "update attributes in the database" do
867
+ doc = @doc.reload
868
+ doc.should == @doc
869
+ doc.first_name.should == 'Johnny'
870
+ doc.age.should == 30
871
+ end
872
+
873
+ should "allow updating custom attributes" do
874
+ @doc.update_attributes(:gender => 'mALe')
875
+ @doc.reload.gender.should == 'mALe'
876
+ end
877
+ end
878
+
879
+ context "Updating an existing document using update attributes" do
880
+ setup do
881
+ @doc = @document.create(:first_name => 'John', :age => '27')
882
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
883
+ end
884
+
885
+ should "not insert document into collection" do
886
+ @document.count.should == 1
887
+ end
888
+
889
+ should "update attributes" do
890
+ @doc.first_name.should == 'Johnny'
891
+ @doc.age.should == 30
892
+ end
893
+
894
+ should "update attributes in the database" do
895
+ doc = @doc.reload
896
+ doc.first_name.should == 'Johnny'
897
+ doc.age.should == 30
898
+ end
899
+ end
900
+
901
+ context "update_attributes" do
902
+ setup do
903
+ @document.key :foo, String, :required => true
904
+ end
905
+
906
+ should "return true if document valid" do
907
+ @document.new.update_attributes(:foo => 'bar').should be_true
908
+ end
909
+
910
+ should "return false if document not valid" do
911
+ @document.new.update_attributes({}).should be_false
912
+ end
913
+ end
914
+
915
+ context "Destroying a document that exists" do
916
+ setup do
917
+ @doc = @document.create(:first_name => 'John', :age => '27')
918
+ @doc.destroy
919
+ end
920
+
921
+ should "remove the document from the collection" do
922
+ @document.count.should == 0
923
+ end
924
+
925
+ should "raise error if assignment is attempted" do
926
+ lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
927
+ end
928
+
929
+ should "do nothing if destroy is called again" do
930
+ @doc.destroy.should be_false
931
+ end
932
+ end
933
+
934
+ context "Destroying a document that is a new" do
935
+ setup do
936
+ setup do
937
+ @doc = @document.new(:first_name => 'John Nunemaker', :age => '27')
938
+ @doc.destroy
939
+ end
940
+
941
+ should "not affect collection count" do
942
+ @document.collection.count.should == 0
943
+ end
944
+
945
+ should "raise error if assignment is attempted" do
946
+ lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
947
+ end
948
+ end
949
+ end
950
+
951
+ context "Single collection inheritance" do
952
+ setup do
953
+ class ::DocParent
954
+ include MongoMapper::Document
955
+ key :_type, String
956
+ key :name, String
957
+ end
958
+ DocParent.collection.remove
959
+
960
+ class ::DocDaughter < ::DocParent; end
961
+ class ::DocSon < ::DocParent; end
962
+ class ::DocGrandSon < ::DocSon; end
963
+
964
+ @parent = DocParent.new({:name => "Daddy Warbucks"})
965
+ @daughter = DocDaughter.new({:name => "Little Orphan Annie"})
966
+ end
967
+
968
+ teardown do
969
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
970
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
971
+ Object.send :remove_const, 'DocSon' if defined?(::DocSon)
972
+ Object.send :remove_const, 'DocGrandSon' if defined?(::DocGrandSon)
973
+ end
974
+
975
+ should "use the same collection in the subclass" do
976
+ DocDaughter.collection.name.should == DocParent.collection.name
977
+ end
978
+
979
+ should "assign the class name into the _type property" do
980
+ @parent._type.should == 'DocParent'
981
+ @daughter._type.should == 'DocDaughter'
982
+ end
983
+
984
+ should "load the document with the assigned type" do
985
+ @parent.save
986
+ @daughter.save
987
+
988
+ collection = DocParent.find(:all)
989
+ collection.size.should == 2
990
+ collection.first.should be_kind_of(DocParent)
991
+ collection.first.name.should == "Daddy Warbucks"
992
+ collection.last.should be_kind_of(DocDaughter)
993
+ collection.last.name.should == "Little Orphan Annie"
994
+ end
995
+
996
+ should "gracefully handle when the type can't be constantized" do
997
+ doc = DocParent.new(:name => 'Nunes')
998
+ doc._type = 'FoobarBaz'
999
+ doc.save
1000
+
1001
+ collection = DocParent.all
1002
+ collection.last.should == doc
1003
+ collection.last.should be_kind_of(DocParent)
1004
+ end
1005
+
1006
+ should "find scoped to class" do
1007
+ john = DocSon.create(:name => 'John')
1008
+ steve = DocSon.create(:name => 'Steve')
1009
+ steph = DocDaughter.create(:name => 'Steph')
1010
+ carrie = DocDaughter.create(:name => 'Carrie')
1011
+
1012
+ DocGrandSon.all(:order => 'name').should == []
1013
+ DocSon.all(:order => 'name').should == [john, steve]
1014
+ DocDaughter.all(:order => 'name').should == [carrie, steph]
1015
+ DocParent.all(:order => 'name').should == [carrie, john, steph, steve]
1016
+ end
1017
+
1018
+ should "work with nested hash conditions" do
1019
+ john = DocSon.create(:name => 'John')
1020
+ steve = DocSon.create(:name => 'Steve')
1021
+ DocSon.all(:name => {'$ne' => 'Steve'}).should == [john]
1022
+ end
1023
+
1024
+ should "raise error if not found scoped to class" do
1025
+ john = DocSon.create(:name => 'John')
1026
+ steph = DocDaughter.create(:name => 'Steph')
1027
+
1028
+ lambda {
1029
+ DocSon.find!(steph._id)
1030
+ }.should raise_error(MongoMapper::DocumentNotFound)
1031
+ end
1032
+
1033
+ should "not raise error for find with parent" do
1034
+ john = DocSon.create(:name => 'John')
1035
+
1036
+ DocParent.find!(john._id).should == john
1037
+ end
1038
+
1039
+ should "count scoped to class" do
1040
+ john = DocSon.create(:name => 'John')
1041
+ steve = DocSon.create(:name => 'Steve')
1042
+ steph = DocDaughter.create(:name => 'Steph')
1043
+ carrie = DocDaughter.create(:name => 'Carrie')
1044
+
1045
+ DocGrandSon.count.should == 0
1046
+ DocSon.count.should == 2
1047
+ DocDaughter.count.should == 2
1048
+ DocParent.count.should == 4
1049
+ end
1050
+
1051
+ should "know if it is single_collection_inherited?" do
1052
+ DocParent.single_collection_inherited?.should be_false
1053
+
1054
+ DocDaughter.single_collection_inherited?.should be_true
1055
+ DocSon.single_collection_inherited?.should be_true
1056
+ end
1057
+
1058
+ should "know if single_collection_inherited_superclass?" do
1059
+ DocParent.single_collection_inherited_superclass?.should be_false
1060
+
1061
+ DocDaughter.single_collection_inherited_superclass?.should be_true
1062
+ DocSon.single_collection_inherited_superclass?.should be_true
1063
+ DocGrandSon.single_collection_inherited_superclass?.should be_true
1064
+ end
1065
+
1066
+ should "not be able to destroy each other" do
1067
+ john = DocSon.create(:name => 'John')
1068
+ steph = DocDaughter.create(:name => 'Steph')
1069
+
1070
+ lambda {
1071
+ DocSon.destroy(steph._id)
1072
+ }.should raise_error(MongoMapper::DocumentNotFound)
1073
+ end
1074
+
1075
+ should "not be able to delete each other" do
1076
+ john = DocSon.create(:name => 'John')
1077
+ steph = DocDaughter.create(:name => 'Steph')
1078
+
1079
+ lambda {
1080
+ DocSon.delete(steph._id)
1081
+ }.should_not change { DocParent.count }
1082
+ end
1083
+
1084
+ should "be able to destroy using parent" do
1085
+ john = DocSon.create(:name => 'John')
1086
+ steph = DocDaughter.create(:name => 'Steph')
1087
+
1088
+ lambda {
1089
+ DocParent.destroy_all
1090
+ }.should change { DocParent.count }.by(-2)
1091
+ end
1092
+
1093
+ should "be able to delete using parent" do
1094
+ john = DocSon.create(:name => 'John')
1095
+ steph = DocDaughter.create(:name => 'Steph')
1096
+
1097
+ lambda {
1098
+ DocParent.delete_all
1099
+ }.should change { DocParent.count }.by(-2)
1100
+ end
1101
+ end
1102
+
1103
+ context "timestamping" do
1104
+ setup do
1105
+ @document.timestamps!
1106
+ end
1107
+
1108
+ should "set created_at and updated_at on create" do
1109
+ doc = @document.new(:first_name => 'John', :age => 27)
1110
+ doc.created_at.should be(nil)
1111
+ doc.updated_at.should be(nil)
1112
+ doc.save
1113
+ doc.created_at.should_not be(nil)
1114
+ doc.updated_at.should_not be(nil)
1115
+ end
1116
+
1117
+ should "set updated_at on field update but leave created_at alone" do
1118
+ doc = @document.create(:first_name => 'John', :age => 27)
1119
+ old_created_at = doc.created_at
1120
+ old_updated_at = doc.updated_at
1121
+ doc.first_name = 'Johnny'
1122
+
1123
+ Timecop.freeze(Time.now + 5.seconds) do
1124
+ doc.save
1125
+ end
1126
+
1127
+ doc.created_at.should == old_created_at
1128
+ doc.updated_at.should_not == old_updated_at
1129
+ end
1130
+
1131
+ should "set updated_at on document update but leave created_at alone" do
1132
+ doc = @document.create(:first_name => 'John', :age => 27)
1133
+ old_created_at = doc.created_at
1134
+ old_updated_at = doc.updated_at
1135
+
1136
+ Timecop.freeze(Time.now + 5.seconds) do
1137
+ @document.update(doc._id, { :first_name => 'Johnny' })
1138
+ end
1139
+
1140
+ doc = doc.reload
1141
+ doc.created_at.should == old_created_at
1142
+ doc.updated_at.should_not == old_updated_at
1143
+ end
1144
+ end
1145
+
1146
+ context "#exist?" do
1147
+ setup do
1148
+ @doc = @document.create(:first_name => "James", :age => 27)
1149
+ end
1150
+
1151
+ should "be true when at least one document exists" do
1152
+ @document.exists?.should == true
1153
+ end
1154
+
1155
+ should "be false when no documents exist" do
1156
+ @doc.destroy
1157
+ @document.exists?.should == false
1158
+ end
1159
+
1160
+ should "be true when at least one document exists that matches the conditions" do
1161
+ @document.exists?(:first_name => "James").should == true
1162
+ end
1163
+
1164
+ should "be false when no documents exist with the provided conditions" do
1165
+ @document.exists?(:first_name => "Jean").should == false
1166
+ end
1167
+ end
1168
+
1169
+ context "reload" do
1170
+ setup do
1171
+ @doc_instance_1 = @document.create({:first_name => 'Ryan', :last_name => 'Koopmans', :age => '37'})
1172
+ @doc_instance_2 = @document.update(@doc_instance_1._id, {:age => '39'})
1173
+ end
1174
+
1175
+ should "load fresh information from the database" do
1176
+ @doc_instance_1.age.should == 37
1177
+ @doc_instance_1.reload.age.should == 39
1178
+ end
1179
+ end
1180
+ end