djsun-mongomapper 0.3.5.5 → 0.4.1.2

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 (44) hide show
  1. data/README.rdoc +38 -38
  2. data/Rakefile +87 -73
  3. data/VERSION +1 -1
  4. data/lib/mongomapper.rb +67 -71
  5. data/lib/mongomapper/associations.rb +86 -84
  6. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -34
  7. data/lib/mongomapper/associations/many_embedded_proxy.rb +67 -17
  8. data/lib/mongomapper/associations/proxy.rb +74 -73
  9. data/lib/mongomapper/document.rb +342 -348
  10. data/lib/mongomapper/embedded_document.rb +354 -274
  11. data/lib/mongomapper/finder_options.rb +84 -84
  12. data/lib/mongomapper/key.rb +32 -76
  13. data/lib/mongomapper/rails_compatibility/document.rb +14 -14
  14. data/lib/mongomapper/rails_compatibility/embedded_document.rb +26 -24
  15. data/lib/mongomapper/support.rb +156 -29
  16. data/lib/mongomapper/validations.rb +69 -47
  17. data/test/custom_matchers.rb +48 -0
  18. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -56
  19. data/test/functional/associations/test_belongs_to_proxy.rb +48 -49
  20. data/test/functional/associations/test_many_documents_as_proxy.rb +208 -253
  21. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +130 -130
  22. data/test/functional/associations/test_many_embedded_proxy.rb +168 -106
  23. data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -262
  24. data/test/functional/test_binary.rb +21 -0
  25. data/test/functional/test_document.rb +946 -952
  26. data/test/functional/test_embedded_document.rb +98 -0
  27. data/test/functional/test_pagination.rb +87 -80
  28. data/test/functional/test_rails_compatibility.rb +29 -29
  29. data/test/functional/test_validations.rb +262 -172
  30. data/test/models.rb +169 -169
  31. data/test/test_helper.rb +28 -66
  32. data/test/unit/serializers/test_json_serializer.rb +193 -193
  33. data/test/unit/test_document.rb +161 -123
  34. data/test/unit/test_embedded_document.rb +643 -547
  35. data/test/unit/test_finder_options.rb +183 -183
  36. data/test/unit/test_key.rb +175 -247
  37. data/test/unit/test_rails_compatibility.rb +38 -33
  38. data/test/unit/test_serializations.rb +52 -52
  39. data/test/unit/test_support.rb +268 -0
  40. data/test/unit/test_time_zones.rb +40 -0
  41. data/test/unit/test_validations.rb +499 -258
  42. metadata +22 -12
  43. data/History +0 -76
  44. data/mongomapper.gemspec +0 -145
@@ -0,0 +1,21 @@
1
+ require 'test_helper'
2
+
3
+ class BinaryTest < Test::Unit::TestCase
4
+ def setup
5
+ clear_all_collections
6
+ end
7
+
8
+ should "serialize and deserialize correctly" do
9
+ klass = Class.new do
10
+ include MongoMapper::Document
11
+ set_collection_name 'test'
12
+ key :contents, Binary
13
+ end
14
+
15
+ doc = klass.new(:contents => '010101')
16
+ doc.save
17
+
18
+ doc = klass.find(doc.id)
19
+ doc.contents.to_s.should == ByteBuffer.new('010101').to_s
20
+ end
21
+ end
@@ -1,952 +1,946 @@
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
- collection 'users'
9
-
10
- key :first_name, String
11
- key :last_name, String
12
- key :age, Integer
13
- end
14
-
15
- @document.collection.clear
16
- end
17
-
18
- context "Saving a document with a custom id" do
19
- should "clear custom id flag when saved" do
20
- doc = @document.new(:id => '1234')
21
- doc.using_custom_id?.should be_true
22
- doc.save.should be_true
23
- doc.using_custom_id?.should be_false
24
- end
25
- end
26
-
27
- context "Loading a document from the database with keys that are not defined" do
28
- setup do
29
- @id = Mongo::ObjectID.new.to_s
30
- @document.collection.insert({
31
- :_id => @id,
32
- :first_name => 'John',
33
- :last_name => 'Nunemaker',
34
- :age => 27,
35
- :favorite_color => 'red',
36
- :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
37
- })
38
- end
39
-
40
- should "assign all keys from database" do
41
- doc = @document.find(@id)
42
- doc.first_name.should == 'John'
43
- doc.last_name.should == 'Nunemaker'
44
- doc.age.should == 27
45
- doc.favorite_color.should == 'red'
46
- doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
47
- end
48
- end
49
-
50
- context "Document Class Methods" do
51
- context "Using key with type Array" do
52
- setup do
53
- @document.key :tags, Array
54
- end
55
-
56
- should "give correct default" do
57
- doc = @document.new
58
- doc.tags.should == []
59
- end
60
-
61
- should "work with assignment" do
62
- doc = @document.new
63
- doc.tags = %w(foo bar)
64
- doc.tags.should == %w(foo bar)
65
- end
66
-
67
- should "work with assignment after saving" do
68
- doc = @document.new
69
- doc.tags = %w(foo bar)
70
- doc.save
71
- doc.tags.should == %w(foo bar)
72
- @document.find(doc.id).tags.should == %w(foo bar)
73
- end
74
-
75
- should "work with assignment then <<" do
76
- doc = @document.new
77
- doc.tags = []
78
- doc.tags << "foo"
79
- doc.tags.should == ["foo"]
80
- end
81
-
82
- should "work with <<" do
83
- doc = @document.new
84
- doc.tags << "foo"
85
- doc.tags.should == ["foo"]
86
- end
87
-
88
- should "work with << then save" do
89
- doc = @document.new
90
- doc.tags << "foo"
91
- doc.tags << "bar"
92
- doc.save
93
- doc.tags.should == %w(foo bar)
94
- @document.find(doc.id).tags.should == %w(foo bar)
95
- end
96
- end
97
-
98
- context "Using key with type Hash" do
99
- setup do
100
- @document.key :foo, Hash
101
- end
102
-
103
- should "give correct default" do
104
- doc = @document.new
105
- doc.foo.should == {}
106
- end
107
-
108
- should "work with []=" do
109
- doc = @document.new
110
- doc.foo["quux"] = "bar"
111
- doc.foo["quux"].should == "bar"
112
- doc.foo.should == { "quux" => "bar" }
113
- end
114
-
115
- should "work with indifferent access" do
116
- doc = @document.new
117
- doc.foo = {:baz => 'bar'}
118
- doc.foo[:baz].should == 'bar'
119
- doc.foo['baz'].should == 'bar'
120
- end
121
-
122
- should "work with indifferent access after save" do
123
- doc = @document.new
124
- doc.foo = {:baz => 'bar'}
125
- doc.save
126
-
127
- doc = @document.find(doc.id)
128
- doc.foo[:baz].should == 'bar'
129
- doc.foo['baz'].should == 'bar'
130
- end
131
- end
132
-
133
- context "Saving a document with an embedded document" do
134
- setup do
135
- @document.class_eval do
136
- key :foo, Address
137
- end
138
- end
139
-
140
- should "embed embedded document" do
141
- address = Address.new(:city => 'South Bend', :state => 'IN')
142
- doc = @document.new(:foo => address)
143
- doc.save
144
- doc.foo.city.should == 'South Bend'
145
- doc.foo.state.should == 'IN'
146
-
147
- from_db = @document.find(doc.id)
148
- from_db.foo.city.should == 'South Bend'
149
- from_db.foo.state.should == 'IN'
150
- end
151
- end
152
-
153
- context "Creating a single document" do
154
- setup do
155
- @doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
156
- end
157
-
158
- should "create a document in correct collection" do
159
- @document.count.should == 1
160
- end
161
-
162
- should "automatically set id" do
163
- @doc_instance.id.should_not be_nil
164
- @doc_instance.id.size.should == 24
165
- end
166
-
167
- should "no longer be new?" do
168
- @doc_instance.new?.should be_false
169
- end
170
-
171
- should "return instance of document" do
172
- @doc_instance.should be_instance_of(@document)
173
- @doc_instance.first_name.should == 'John'
174
- @doc_instance.last_name.should == 'Nunemaker'
175
- @doc_instance.age.should == 27
176
- end
177
- end
178
-
179
- context "Creating a document with no attributes provided" do
180
- setup do
181
- @document = Class.new do
182
- include MongoMapper::Document
183
- end
184
- @document.collection.clear
185
- end
186
-
187
- should "create the document" do
188
- lambda {
189
- @document.create
190
- }.should change { @document.count }.by(1)
191
- end
192
- end
193
-
194
- context "Creating multiple documents" do
195
- setup do
196
- @doc_instances = @document.create([
197
- {:first_name => 'John', :last_name => 'Nunemaker', :age => '27'},
198
- {:first_name => 'Steve', :last_name => 'Smith', :age => '28'},
199
- ])
200
- end
201
-
202
- should "create multiple documents" do
203
- @document.count.should == 2
204
- end
205
-
206
- should "return an array of doc instances" do
207
- @doc_instances.map do |doc_instance|
208
- doc_instance.should be_instance_of(@document)
209
- end
210
- end
211
- end
212
-
213
- context "Updating a document" do
214
- setup do
215
- doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
216
- @doc_instance = @document.update(doc.id, {:age => 40})
217
- end
218
-
219
- should "update attributes provided" do
220
- @doc_instance.age.should == 40
221
- end
222
-
223
- should "not update existing attributes that were not set to update" do
224
- @doc_instance.first_name.should == 'John'
225
- @doc_instance.last_name.should == 'Nunemaker'
226
- end
227
-
228
- should "not create new document" do
229
- @document.count.should == 1
230
- end
231
- end
232
-
233
- should "raise error when updating single doc if not provided id and attributes" do
234
- doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
235
- lambda { @document.update }.should raise_error(ArgumentError)
236
- lambda { @document.update(doc.id) }.should raise_error(ArgumentError)
237
- lambda { @document.update(doc.id, [1]) }.should raise_error(ArgumentError)
238
- end
239
-
240
- context "Updating multiple documents" do
241
- setup do
242
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
243
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
244
-
245
- @doc_instances = @document.update({
246
- @doc1.id => {:age => 30},
247
- @doc2.id => {:age => 30},
248
- })
249
- end
250
-
251
- should "not create any new documents" do
252
- @document.count.should == 2
253
- end
254
-
255
- should "should return an array of doc instances" do
256
- @doc_instances.map do |doc_instance|
257
- doc_instance.should be_instance_of(@document)
258
- end
259
- end
260
-
261
- should "update the documents" do
262
- @document.find(@doc1.id).age.should == 30
263
- @document.find(@doc2.id).age.should == 30
264
- end
265
- end
266
-
267
- should "raise error when updating multiple documents if not a hash" do
268
- lambda { @document.update([1, 2]) }.should raise_error(ArgumentError)
269
- end
270
-
271
- context "Finding documents" do
272
- setup do
273
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
274
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
275
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
276
- end
277
-
278
- should "raise document not found if nothing provided" do
279
- lambda { @document.find }.should raise_error(MongoMapper::DocumentNotFound)
280
- end
281
-
282
- context "with a single id" do
283
- should "work" do
284
- @document.find(@doc1.id).should == @doc1
285
- end
286
-
287
- should "raise error if document not found" do
288
- lambda { @document.find(123) }.should raise_error(MongoMapper::DocumentNotFound)
289
- end
290
- end
291
-
292
- context "with multiple id's" do
293
- should "work as arguments" do
294
- @document.find(@doc1.id, @doc2.id).should == [@doc1, @doc2]
295
- end
296
-
297
- should "work as array" do
298
- @document.find([@doc1.id, @doc2.id]).should == [@doc1, @doc2]
299
- end
300
- end
301
-
302
- context "with :all" do
303
- should "find all documents" do
304
- @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
305
- end
306
-
307
- should "be able to add conditions" do
308
- @document.find(:all, :conditions => {:first_name => 'John'}).should == [@doc1]
309
- end
310
- end
311
-
312
- context "with #all" do
313
- should "find all documents based on criteria" do
314
- @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
315
- @document.all(:conditions => {:last_name => 'Nunemaker'}, :order => 'age desc').should == [@doc1, @doc3]
316
- end
317
- end
318
-
319
- context "with :first" do
320
- should "find first document" do
321
- @document.find(:first, :order => 'first_name').should == @doc1
322
- end
323
- end
324
-
325
- context "with #first" do
326
- should "find first document based on criteria" do
327
- @document.first(:order => 'first_name').should == @doc1
328
- @document.first(:conditions => {:age => 28}).should == @doc2
329
- end
330
- end
331
-
332
- context "with :last" do
333
- should "find last document" do
334
- @document.find(:last, :order => 'age').should == @doc2
335
- end
336
- end
337
-
338
- context "with #last" do
339
- should "find last document based on criteria" do
340
- @document.last(:order => 'age').should == @doc2
341
- @document.last(:conditions => {:age => 28}).should == @doc2
342
- end
343
- end
344
-
345
- context "with :find_by" do
346
- should "find document based on argument" do
347
- @document.find_by_first_name('John').should == @doc1
348
- @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
349
- @document.find_by_age(27).should == @doc1
350
- end
351
-
352
- should "not raise error" do
353
- @document.find_by_first_name('Mongo').should be_nil
354
- end
355
-
356
- should "define a method for each key" do
357
- @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
358
- end
359
- end
360
-
361
- context "with dynamic finders" do
362
- should "find document based on all arguments" do
363
- @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
364
- end
365
-
366
- should "not find the document if an argument is wrong" do
367
- @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
368
- end
369
-
370
- should "find all documents based on arguments" do
371
- docs = @document.find_all_by_last_name('Nunemaker')
372
- docs.should be_kind_of(Array)
373
- docs.should include(@doc1)
374
- docs.should include(@doc3)
375
- end
376
-
377
- should "find last document based on arguments" do
378
- doc = @document.find_last_by_last_name('Nunemaker', :order => 'age')
379
- doc.should == @doc1
380
- end
381
-
382
- should "initialize document with given arguments" do
383
- doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
384
- doc.should be_new
385
- doc.first_name.should == 'David'
386
- end
387
-
388
- should "not initialize document if document is found" do
389
- doc = @document.find_or_initialize_by_first_name('John')
390
- doc.should_not be_new
391
- end
392
-
393
- should "create document with given arguments" do
394
- doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
395
- doc.should_not be_new
396
- doc.first_name.should == 'David'
397
- end
398
-
399
- should "raise error if document is not found" do
400
- lambda {@document.find_by_first_name_and_last_name!(1,2)}.should raise_error(MongoMapper::DocumentNotFound)
401
- end
402
- end
403
- end # finding documents
404
-
405
- context "Finding document by id" do
406
- setup do
407
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
408
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
409
- end
410
-
411
- should "be able to find by id" do
412
- @document.find_by_id(@doc1.id).should == @doc1
413
- @document.find_by_id(@doc2.id).should == @doc2
414
- end
415
-
416
- should "return nil if document not found" do
417
- @document.find_by_id(1234).should be(nil)
418
- end
419
- end
420
-
421
- context "Deleting a document" do
422
- setup do
423
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
424
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
425
- @document.delete(@doc1.id)
426
- end
427
-
428
- should "remove document from collection" do
429
- @document.count.should == 1
430
- end
431
-
432
- should "not remove other documents" do
433
- @document.find(@doc2.id).should_not be(nil)
434
- end
435
- end
436
-
437
- context "Deleting multiple documents" do
438
- should "work with multiple arguments" do
439
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
440
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
441
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
442
- @document.delete(@doc1.id, @doc2.id)
443
-
444
- @document.count.should == 1
445
- end
446
-
447
- should "work with array as argument" do
448
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
449
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
450
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
451
- @document.delete([@doc1.id, @doc2.id])
452
-
453
- @document.count.should == 1
454
- end
455
- end
456
-
457
- context "Deleting all documents" do
458
- setup do
459
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
460
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
461
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
462
- end
463
-
464
- should "remove all documents when given no conditions" do
465
- @document.delete_all
466
- @document.count.should == 0
467
- end
468
-
469
- should "only remove matching documents when given conditions" do
470
- @document.delete_all({:first_name => 'John'})
471
- @document.count.should == 2
472
- end
473
-
474
- should "convert the conditions to mongo criteria" do
475
- @document.delete_all(:age => [26, 27])
476
- @document.count.should == 1
477
- end
478
- end
479
-
480
- context "Destroying a document" do
481
- setup do
482
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
483
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
484
- @document.destroy(@doc1.id)
485
- end
486
-
487
- should "remove document from collection" do
488
- @document.count.should == 1
489
- end
490
-
491
- should "not remove other documents" do
492
- @document.find(@doc2.id).should_not be(nil)
493
- end
494
- end
495
-
496
- context "Destroying multiple documents" do
497
- should "work with multiple arguments" do
498
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
499
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
500
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
501
- @document.destroy(@doc1.id, @doc2.id)
502
-
503
- @document.count.should == 1
504
- end
505
-
506
- should "work with array as argument" do
507
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
508
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
509
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
510
- @document.destroy([@doc1.id, @doc2.id])
511
-
512
- @document.count.should == 1
513
- end
514
- end
515
-
516
- context "Destroying all documents" do
517
- setup do
518
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
519
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
520
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
521
- end
522
-
523
- should "remove all documents when given no conditions" do
524
- @document.destroy_all
525
- @document.count.should == 0
526
- end
527
-
528
- should "only remove matching documents when given conditions" do
529
- @document.destroy_all(:first_name => 'John')
530
- @document.count.should == 2
531
- @document.destroy_all(:age => 26)
532
- @document.count.should == 1
533
- end
534
-
535
- should "convert the conditions to mongo criteria" do
536
- @document.destroy_all(:age => [26, 27])
537
- @document.count.should == 1
538
- end
539
- end
540
-
541
- context ":dependent" do
542
- setup do
543
- # FIXME: make use of already defined models
544
- class ::Property
545
- include MongoMapper::Document
546
- end
547
- Property.delete_all
548
-
549
- class ::Thing
550
- include MongoMapper::Document
551
- key :name, String
552
- end
553
- Thing.delete_all
554
- end
555
-
556
- teardown do
557
- Object.send :remove_const, 'Property' if defined?(::Property)
558
- Object.send :remove_const, 'Thing' if defined?(::Thing)
559
- end
560
-
561
- context "many" do
562
- context "=> destroy" do
563
- setup do
564
- Property.key :thing_id, String
565
- Property.belongs_to :thing, :dependent => :destroy
566
- Thing.many :properties, :dependent => :destroy
567
-
568
- @thing = Thing.create(:name => "Tree")
569
- @property1 = Property.create
570
- @property2 = Property.create
571
- @property3 = Property.create
572
- @thing.properties << @property1
573
- @thing.properties << @property2
574
- @thing.properties << @property3
575
- end
576
-
577
- should "should destroy the associated documents" do
578
- @thing.properties.count.should == 3
579
- @thing.destroy
580
- @thing.properties.count.should == 0
581
- Property.count.should == 0
582
- end
583
- end
584
-
585
- context "=> delete_all" do
586
- setup do
587
- Property.key :thing_id, String
588
- Property.belongs_to :thing
589
- Thing.has_many :properties, :dependent => :delete_all
590
-
591
- @thing = Thing.create(:name => "Tree")
592
- @property1 = Property.create
593
- @property2 = Property.create
594
- @property3 = Property.create
595
- @thing.properties << @property1
596
- @thing.properties << @property2
597
- @thing.properties << @property3
598
- end
599
-
600
- should "should delete associated documents" do
601
- @thing.properties.count.should == 3
602
- @thing.destroy
603
- @thing.properties.count.should == 0
604
- Property.count.should == 0
605
- end
606
- end
607
-
608
- context "=> nullify" do
609
- setup do
610
- Property.key :thing_id, String
611
- Property.belongs_to :thing
612
- Thing.has_many :properties, :dependent => :nullify
613
-
614
- @thing = Thing.create(:name => "Tree")
615
- @property1 = Property.create
616
- @property2 = Property.create
617
- @property3 = Property.create
618
- @thing.properties << @property1
619
- @thing.properties << @property2
620
- @thing.properties << @property3
621
- end
622
-
623
- should "should nullify relationship but not destroy associated documents" do
624
- @thing.properties.count.should == 3
625
- @thing.destroy
626
- @thing.properties.count.should == 0
627
- Property.count.should == 3
628
- end
629
- end
630
- end
631
-
632
- context "belongs_to" do
633
- context "=> destroy" do
634
- setup do
635
- Property.key :thing_id, String
636
- Property.belongs_to :thing, :dependent => :destroy
637
- Thing.has_many :properties
638
-
639
- @thing = Thing.create(:name => "Tree")
640
- @property1 = Property.create
641
- @property2 = Property.create
642
- @property3 = Property.create
643
- @thing.properties << @property1
644
- @thing.properties << @property2
645
- @thing.properties << @property3
646
- end
647
-
648
- should "destroy the thing" do
649
- Thing.count.should == 1
650
- @property1.destroy
651
- Thing.count.should == 0
652
- @property1.thing.should be_frozen
653
- end
654
- end
655
- end
656
- end
657
-
658
- context "Counting documents in collection" do
659
- setup do
660
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
661
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
662
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
663
- end
664
-
665
- should "count all with no arguments" do
666
- @document.count.should == 3
667
- end
668
-
669
- should "return 0 if there are no documents in the collection" do
670
- @document.delete_all
671
- @document.count.should == 0
672
- end
673
-
674
- should "return 0 if the collection does not exist" do
675
- klass = Class.new do
676
- include MongoMapper::Document
677
- collection 'foobarbazwickdoesnotexist'
678
- end
679
-
680
- klass.count.should == 0
681
- end
682
-
683
- should "return count for matching documents if conditions provided" do
684
- @document.count(:age => 27).should == 1
685
- end
686
-
687
- should "convert the conditions to mongo criteria" do
688
- @document.count(:age => [26, 27]).should == 2
689
- end
690
- end
691
-
692
- context "Indexing" do
693
- setup do
694
- @document.collection.drop_indexes
695
- end
696
-
697
- should "allow creating index for a key" do
698
- index_name = nil
699
- lambda {
700
- index_name = @document.ensure_index :first_name
701
- }.should change { @document.collection.index_information.size }.by(1)
702
-
703
- index_name.should == 'first_name_1'
704
- index = @document.collection.index_information[index_name]
705
- index.should_not be_nil
706
- index.should include(['first_name', 1])
707
- end
708
-
709
- should "allow creating unique index for a key" do
710
- @document.collection.expects(:create_index).with(:first_name, true)
711
- @document.ensure_index :first_name, :unique => true
712
- end
713
-
714
- should "allow creating index on multiple keys" do
715
- index_name = nil
716
- lambda {
717
- index_name = @document.ensure_index [[:first_name, 1], [:last_name, -1]]
718
- }.should change { @document.collection.index_information.size }.by(1)
719
-
720
- [ 'first_name_1_last_name_-1', 'last_name_-1_first_name_1' ].should include(index_name)
721
-
722
- index = @document.collection.index_information[index_name]
723
- index.should_not be_nil
724
- index.should include(['first_name', 1])
725
- index.should include(['last_name', -1])
726
- end
727
-
728
- should "work with :index shortcut when defining key" do
729
- @document.expects(:ensure_index).with('father').returns(nil)
730
- @document.key :father, String, :index => true
731
- end
732
- end
733
- end # Document Class Methods
734
-
735
- context "Saving a new document" do
736
- setup do
737
- @doc = @document.new(:first_name => 'John', :age => '27')
738
- @doc.save
739
- end
740
-
741
- should "insert document into the collection" do
742
- @document.count.should == 1
743
- end
744
-
745
- should "assign an id for the document" do
746
- @doc.id.should_not be(nil)
747
- @doc.id.size.should == 24
748
- end
749
-
750
- should "save attributes" do
751
- @doc.first_name.should == 'John'
752
- @doc.age.should == 27
753
- end
754
-
755
- should "update attributes in the database" do
756
- from_db = @document.find(@doc.id)
757
- from_db.should == @doc
758
- from_db.first_name.should == 'John'
759
- from_db.age.should == 27
760
- end
761
-
762
- should "allow to add custom attributes to the document" do
763
- @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
764
- @doc.save
765
- from_db = @document.find(@doc.id)
766
- from_db.gender.should == 'male'
767
- from_db.tags.should == [1, "2"]
768
- end
769
-
770
- should "allow to use custom methods to assign properties" do
771
- person = RealPerson.new(:realname => "David")
772
- person.save
773
- from_db = RealPerson.find(person.id)
774
- from_db.name.should == "David"
775
- end
776
- end
777
-
778
- context "Saving an existing document" do
779
- setup do
780
- @doc = @document.create(:first_name => 'John', :age => '27')
781
- @doc.first_name = 'Johnny'
782
- @doc.age = 30
783
- @doc.save
784
- end
785
-
786
- should "not insert document into collection" do
787
- @document.count.should == 1
788
- end
789
-
790
- should "update attributes" do
791
- @doc.first_name.should == 'Johnny'
792
- @doc.age.should == 30
793
- end
794
-
795
- should "update attributes in the database" do
796
- from_db = @document.find(@doc.id)
797
- from_db.first_name.should == 'Johnny'
798
- from_db.age.should == 30
799
- end
800
-
801
- should "allow to update custom attributes" do
802
- @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
803
- @doc.gender = 'Male'
804
- @doc.save
805
- from_db = @document.find(@doc.id)
806
- from_db.gender.should == 'Male'
807
- end
808
- end
809
-
810
- context "Calling update attributes on a new document" do
811
- setup do
812
- @doc = @document.new(:first_name => 'John', :age => '27')
813
- @doc.update_attributes(:first_name => 'Johnny', :age => 30)
814
- end
815
-
816
- should "insert document into the collection" do
817
- @document.count.should == 1
818
- end
819
-
820
- should "assign an id for the document" do
821
- @doc.id.should_not be(nil)
822
- @doc.id.size.should == 24
823
- end
824
-
825
- should "save attributes" do
826
- @doc.first_name.should == 'Johnny'
827
- @doc.age.should == 30
828
- end
829
-
830
- should "update attributes in the database" do
831
- from_db = @document.find(@doc.id)
832
- from_db.should == @doc
833
- from_db.first_name.should == 'Johnny'
834
- from_db.age.should == 30
835
- end
836
-
837
- should "allow to update custom attributes" do
838
- @doc.update_attributes(:gender => 'mALe')
839
- from_db = @document.find(@doc.id)
840
- from_db.gender.should == 'mALe'
841
- end
842
- end
843
-
844
- context "Updating an existing document using update attributes" do
845
- setup do
846
- @doc = @document.create(:first_name => 'John', :age => '27')
847
- @doc.update_attributes(:first_name => 'Johnny', :age => 30)
848
- end
849
-
850
- should "not insert document into collection" do
851
- @document.count.should == 1
852
- end
853
-
854
- should "update attributes" do
855
- @doc.first_name.should == 'Johnny'
856
- @doc.age.should == 30
857
- end
858
-
859
- should "update attributes in the database" do
860
- from_db = @document.find(@doc.id)
861
- from_db.first_name.should == 'Johnny'
862
- from_db.age.should == 30
863
- end
864
- end
865
-
866
- context "update_attributes" do
867
- setup do
868
- @document.key :foo, String, :required => true
869
- end
870
-
871
- should "return true if document valid" do
872
- @document.new.update_attributes(:foo => 'bar').should be_true
873
- end
874
-
875
- should "return false if document not valid" do
876
- @document.new.update_attributes({}).should be_false
877
- end
878
- end
879
-
880
- context "Destroying a document that exists" do
881
- setup do
882
- @doc = @document.create(:first_name => 'John', :age => '27')
883
- @doc.destroy
884
- end
885
-
886
- should "remove the document from the collection" do
887
- @document.count.should == 0
888
- end
889
-
890
- should "raise error if assignment is attempted" do
891
- lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
892
- end
893
-
894
- should "do nothing if destroy is called again" do
895
- @doc.destroy.should be_false
896
- end
897
- end
898
-
899
- context "Destroying a document that is a new" do
900
- setup do
901
- setup do
902
- @doc = @document.new(:first_name => 'John Nunemaker', :age => '27')
903
- @doc.destroy
904
- end
905
-
906
- should "not affect collection count" do
907
- @document.collection.count.should == 0
908
- end
909
-
910
- should "raise error if assignment is attempted" do
911
- lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
912
- end
913
- end
914
- end
915
-
916
- context "timestamping" do
917
- setup do
918
- @document.timestamps!
919
- end
920
-
921
- should "set created_at and updated_at on create" do
922
- doc = @document.new(:first_name => 'John', :age => 27)
923
- doc.created_at.should be(nil)
924
- doc.updated_at.should be(nil)
925
- doc.save
926
- doc.created_at.should_not be(nil)
927
- doc.updated_at.should_not be(nil)
928
- end
929
-
930
- should "set updated_at on field update but leave created_at alone" do
931
- doc = @document.create(:first_name => 'John', :age => 27)
932
- old_created_at = doc.created_at
933
- old_updated_at = doc.updated_at
934
- doc.first_name = 'Johnny'
935
- doc.save
936
- doc.created_at.should == old_created_at
937
- doc.updated_at.should_not == old_updated_at
938
- end
939
-
940
- should "set updated_at on document update but leave created_at alone" do
941
- doc = @document.create(:first_name => 'John', :age => 27)
942
- old_created_at = doc.created_at
943
- old_updated_at = doc.updated_at
944
- sleep 1 # this annoys me
945
- @document.update(doc._id, { :first_name => 'Johnny' })
946
-
947
- from_db = @document.find(doc.id)
948
- from_db.created_at.to_i.should == old_created_at.to_i
949
- from_db.updated_at.to_i.should_not == old_updated_at.to_i
950
- end
951
- end
952
- end
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 :nick_name, String, :default => ""
13
+ key :age, Integer
14
+ key :date, Date
15
+ end
16
+
17
+ clear_all_collections
18
+ end
19
+
20
+ context "Saving a document with a custom id" do
21
+ should "clear custom id flag when saved" do
22
+ doc = @document.new(:id => '1234')
23
+ doc.using_custom_id?.should be_true
24
+ doc.save.should be_true
25
+ doc.using_custom_id?.should be_false
26
+ end
27
+ end
28
+
29
+ context "Loading a document from the database with keys that are not defined" do
30
+ setup do
31
+ @id = Mongo::ObjectID.new.to_s
32
+ @document.collection.insert({
33
+ :_id => @id,
34
+ :first_name => 'John',
35
+ :last_name => 'Nunemaker',
36
+ :age => 27,
37
+ :favorite_color => 'red',
38
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
39
+ })
40
+ end
41
+
42
+ should "assign all keys from database" do
43
+ doc = @document.find(@id)
44
+ doc.first_name.should == 'John'
45
+ doc.last_name.should == 'Nunemaker'
46
+ doc.age.should == 27
47
+ doc.favorite_color.should == 'red'
48
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
49
+ end
50
+ end
51
+
52
+ context "Document Class Methods" do
53
+ context "Using key with type Array" do
54
+ setup do
55
+ @document.key :tags, Array
56
+ end
57
+
58
+ should "give correct default" do
59
+ doc = @document.new
60
+ doc.tags.should == []
61
+ end
62
+
63
+ should "work with assignment" do
64
+ doc = @document.new
65
+ doc.tags = %w(foo bar)
66
+ doc.tags.should == %w(foo bar)
67
+ end
68
+
69
+ should "work with assignment after saving" do
70
+ doc = @document.new
71
+ doc.tags = %w(foo bar)
72
+ doc.save
73
+ doc.tags.should == %w(foo bar)
74
+ @document.find(doc.id).tags.should == %w(foo bar)
75
+ end
76
+
77
+ should "work with assignment then <<" do
78
+ doc = @document.new
79
+ doc.tags = []
80
+ doc.tags << "foo"
81
+ doc.tags.should == ["foo"]
82
+ end
83
+
84
+ should "work with <<" do
85
+ doc = @document.new
86
+ doc.tags << "foo"
87
+ doc.tags.should == ["foo"]
88
+ end
89
+
90
+ should "work with << then save" do
91
+ doc = @document.new
92
+ doc.tags << "foo"
93
+ doc.tags << "bar"
94
+ doc.save
95
+ doc.tags.should == %w(foo bar)
96
+ @document.find(doc.id).tags.should == %w(foo bar)
97
+ end
98
+ end
99
+
100
+ context "Using key with type Hash" do
101
+ setup do
102
+ @document.key :foo, Hash
103
+ end
104
+
105
+ should "give correct default" do
106
+ doc = @document.new
107
+ doc.foo.should == {}
108
+ end
109
+
110
+ should "work with []=" do
111
+ doc = @document.new
112
+ doc.foo["quux"] = "bar"
113
+ doc.foo["quux"].should == "bar"
114
+ doc.foo.should == { "quux" => "bar" }
115
+ end
116
+
117
+ should "work with indifferent access" do
118
+ doc = @document.new
119
+ doc.foo = {:baz => 'bar'}
120
+ doc.foo[:baz].should == 'bar'
121
+ doc.foo['baz'].should == 'bar'
122
+ end
123
+
124
+ should "work with indifferent access after save" do
125
+ doc = @document.new
126
+ doc.foo = {:baz => 'bar'}
127
+ doc.save
128
+
129
+ doc = @document.find(doc.id)
130
+ doc.foo[:baz].should == 'bar'
131
+ doc.foo['baz'].should == 'bar'
132
+ end
133
+ end
134
+
135
+ context "Creating a single document" do
136
+ setup do
137
+ @doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
138
+ end
139
+
140
+ should "create a document in correct collection" do
141
+ @document.count.should == 1
142
+ end
143
+
144
+ should "automatically set id" do
145
+ @doc_instance.id.should_not be_nil
146
+ @doc_instance.id.size.should == 24
147
+ end
148
+
149
+ should "no longer be new?" do
150
+ @doc_instance.new?.should be_false
151
+ end
152
+
153
+ should "return instance of document" do
154
+ @doc_instance.should be_instance_of(@document)
155
+ @doc_instance.first_name.should == 'John'
156
+ @doc_instance.last_name.should == 'Nunemaker'
157
+ @doc_instance.age.should == 27
158
+ end
159
+ end
160
+
161
+ context "Creating a document with no attributes provided" do
162
+ setup do
163
+ @document = Class.new do
164
+ include MongoMapper::Document
165
+ end
166
+ end
167
+
168
+ should "create the document" do
169
+ lambda {
170
+ @document.create
171
+ }.should change { @document.count }.by(1)
172
+ end
173
+ end
174
+
175
+ context "Creating multiple documents" do
176
+ setup do
177
+ @doc_instances = @document.create([
178
+ {:first_name => 'John', :last_name => 'Nunemaker', :age => '27'},
179
+ {:first_name => 'Steve', :last_name => 'Smith', :age => '28'},
180
+ ])
181
+ end
182
+
183
+ should "create multiple documents" do
184
+ @document.count.should == 2
185
+ end
186
+
187
+ should "return an array of doc instances" do
188
+ @doc_instances.map do |doc_instance|
189
+ doc_instance.should be_instance_of(@document)
190
+ end
191
+ end
192
+ end
193
+
194
+ context "Updating a document" do
195
+ setup do
196
+ doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
197
+ @doc_instance = @document.update(doc.id, {:age => 40})
198
+ end
199
+
200
+ should "update attributes provided" do
201
+ @doc_instance.age.should == 40
202
+ end
203
+
204
+ should "not update existing attributes that were not set to update" do
205
+ @doc_instance.first_name.should == 'John'
206
+ @doc_instance.last_name.should == 'Nunemaker'
207
+ end
208
+
209
+ should "not create new document" do
210
+ @document.count.should == 1
211
+ end
212
+ end
213
+
214
+ should "raise error when updating single doc if not provided id and attributes" do
215
+ doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
216
+ lambda { @document.update }.should raise_error(ArgumentError)
217
+ lambda { @document.update(doc.id) }.should raise_error(ArgumentError)
218
+ lambda { @document.update(doc.id, [1]) }.should raise_error(ArgumentError)
219
+ end
220
+
221
+ context "Updating multiple documents" do
222
+ setup do
223
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
224
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
225
+
226
+ @doc_instances = @document.update({
227
+ @doc1.id => {:age => 30},
228
+ @doc2.id => {:age => 30},
229
+ })
230
+ end
231
+
232
+ should "not create any new documents" do
233
+ @document.count.should == 2
234
+ end
235
+
236
+ should "should return an array of doc instances" do
237
+ @doc_instances.map do |doc_instance|
238
+ doc_instance.should be_instance_of(@document)
239
+ end
240
+ end
241
+
242
+ should "update the documents" do
243
+ @document.find(@doc1.id).age.should == 30
244
+ @document.find(@doc2.id).age.should == 30
245
+ end
246
+ end
247
+
248
+ should "raise error when updating multiple documents if not a hash" do
249
+ lambda { @document.update([1, 2]) }.should raise_error(ArgumentError)
250
+ end
251
+
252
+ context "Finding documents" do
253
+ setup do
254
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
255
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
256
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
257
+ end
258
+
259
+ should "raise document not found if nothing provided" do
260
+ lambda { @document.find }.should raise_error(MongoMapper::DocumentNotFound)
261
+ end
262
+
263
+ context "with a single id" do
264
+ should "work" do
265
+ @document.find(@doc1.id).should == @doc1
266
+ end
267
+
268
+ should "raise error if document not found" do
269
+ lambda { @document.find(123) }.should raise_error(MongoMapper::DocumentNotFound)
270
+ end
271
+ end
272
+
273
+ context "with multiple id's" do
274
+ should "work as arguments" do
275
+ @document.find(@doc1.id, @doc2.id).should == [@doc1, @doc2]
276
+ end
277
+
278
+ should "work as array" do
279
+ @document.find([@doc1.id, @doc2.id]).should == [@doc1, @doc2]
280
+ end
281
+ end
282
+
283
+ context "with :all" do
284
+ should "find all documents" do
285
+ @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
286
+ end
287
+
288
+ should "be able to add conditions" do
289
+ @document.find(:all, :conditions => {:first_name => 'John'}).should == [@doc1]
290
+ end
291
+ end
292
+
293
+ context "with #all" do
294
+ should "find all documents based on criteria" do
295
+ @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
296
+ @document.all(:conditions => {:last_name => 'Nunemaker'}, :order => 'age desc').should == [@doc1, @doc3]
297
+ end
298
+ end
299
+
300
+ context "with :first" do
301
+ should "find first document" do
302
+ @document.find(:first, :order => 'first_name').should == @doc1
303
+ end
304
+ end
305
+
306
+ context "with #first" do
307
+ should "find first document based on criteria" do
308
+ @document.first(:order => 'first_name').should == @doc1
309
+ @document.first(:conditions => {:age => 28}).should == @doc2
310
+ end
311
+ end
312
+
313
+ context "with :last" do
314
+ should "find last document" do
315
+ @document.find(:last, :order => 'age').should == @doc2
316
+ end
317
+ end
318
+
319
+ context "with #last" do
320
+ should "find last document based on criteria" do
321
+ @document.last(:order => 'age').should == @doc2
322
+ @document.last(:conditions => {:age => 28}).should == @doc2
323
+ end
324
+ end
325
+
326
+ context "with :find_by" do
327
+ should "find document based on argument" do
328
+ @document.find_by_first_name('John').should == @doc1
329
+ @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
330
+ @document.find_by_age(27).should == @doc1
331
+ end
332
+
333
+ should "not raise error" do
334
+ @document.find_by_first_name('Mongo').should be_nil
335
+ end
336
+
337
+ should "define a method for each key" do
338
+ @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
339
+ end
340
+ end
341
+
342
+ context "with dynamic finders" do
343
+ should "find document based on all arguments" do
344
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
345
+ end
346
+
347
+ should "not find the document if an argument is wrong" do
348
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
349
+ end
350
+
351
+ should "find all documents based on arguments" do
352
+ docs = @document.find_all_by_last_name('Nunemaker')
353
+ docs.should be_kind_of(Array)
354
+ docs.should include(@doc1)
355
+ docs.should include(@doc3)
356
+ end
357
+
358
+ should "find last document based on arguments" do
359
+ doc = @document.find_last_by_last_name('Nunemaker', :order => 'age')
360
+ doc.should == @doc1
361
+ end
362
+
363
+ should "initialize document with given arguments" do
364
+ doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
365
+ doc.should be_new
366
+ doc.first_name.should == 'David'
367
+ end
368
+
369
+ should "not initialize document if document is found" do
370
+ doc = @document.find_or_initialize_by_first_name('John')
371
+ doc.should_not be_new
372
+ end
373
+
374
+ should "create document with given arguments" do
375
+ doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
376
+ doc.should_not be_new
377
+ doc.first_name.should == 'David'
378
+ end
379
+
380
+ should "raise error if document is not found" do
381
+ lambda {@document.find_by_first_name_and_last_name!(1,2)}.should raise_error(MongoMapper::DocumentNotFound)
382
+ end
383
+ end
384
+ end # finding documents
385
+
386
+ context "Finding document by id" do
387
+ setup do
388
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
389
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
390
+ end
391
+
392
+ should "be able to find by id" do
393
+ @document.find_by_id(@doc1.id).should == @doc1
394
+ @document.find_by_id(@doc2.id).should == @doc2
395
+ end
396
+
397
+ should "return nil if document not found" do
398
+ @document.find_by_id(1234).should be(nil)
399
+ end
400
+ end
401
+
402
+ context "Deleting a document" do
403
+ setup do
404
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
405
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
406
+ @document.delete(@doc1.id)
407
+ end
408
+
409
+ should "remove document from collection" do
410
+ @document.count.should == 1
411
+ end
412
+
413
+ should "not remove other documents" do
414
+ @document.find(@doc2.id).should_not be(nil)
415
+ end
416
+ end
417
+
418
+ context "Deleting multiple documents" do
419
+ should "work with multiple arguments" do
420
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
421
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
422
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
423
+ @document.delete(@doc1.id, @doc2.id)
424
+
425
+ @document.count.should == 1
426
+ end
427
+
428
+ should "work with array as argument" do
429
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
430
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
431
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
432
+ @document.delete([@doc1.id, @doc2.id])
433
+
434
+ @document.count.should == 1
435
+ end
436
+ end
437
+
438
+ context "Deleting all documents" 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
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
443
+ end
444
+
445
+ should "remove all documents when given no conditions" do
446
+ @document.delete_all
447
+ @document.count.should == 0
448
+ end
449
+
450
+ should "only remove matching documents when given conditions" do
451
+ @document.delete_all({:first_name => 'John'})
452
+ @document.count.should == 2
453
+ end
454
+
455
+ should "convert the conditions to mongo criteria" do
456
+ @document.delete_all(:age => [26, 27])
457
+ @document.count.should == 1
458
+ end
459
+ end
460
+
461
+ context "Destroying a document" do
462
+ setup do
463
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
464
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
465
+ @document.destroy(@doc1.id)
466
+ end
467
+
468
+ should "remove document from collection" do
469
+ @document.count.should == 1
470
+ end
471
+
472
+ should "not remove other documents" do
473
+ @document.find(@doc2.id).should_not be(nil)
474
+ end
475
+ end
476
+
477
+ context "Destroying multiple documents" do
478
+ should "work with multiple arguments" do
479
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
480
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
481
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
482
+ @document.destroy(@doc1.id, @doc2.id)
483
+
484
+ @document.count.should == 1
485
+ end
486
+
487
+ should "work with array as argument" do
488
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
489
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
490
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
491
+ @document.destroy([@doc1.id, @doc2.id])
492
+
493
+ @document.count.should == 1
494
+ end
495
+ end
496
+
497
+ context "Destroying all documents" do
498
+ setup do
499
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
500
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
501
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
502
+ end
503
+
504
+ should "remove all documents when given no conditions" do
505
+ @document.destroy_all
506
+ @document.count.should == 0
507
+ end
508
+
509
+ should "only remove matching documents when given conditions" do
510
+ @document.destroy_all(:first_name => 'John')
511
+ @document.count.should == 2
512
+ @document.destroy_all(:age => 26)
513
+ @document.count.should == 1
514
+ end
515
+
516
+ should "convert the conditions to mongo criteria" do
517
+ @document.destroy_all(:age => [26, 27])
518
+ @document.count.should == 1
519
+ end
520
+ end
521
+
522
+ context ":dependent" do
523
+ setup do
524
+ # FIXME: make use of already defined models
525
+ class ::Property
526
+ include MongoMapper::Document
527
+ end
528
+ Property.delete_all
529
+
530
+ class ::Thing
531
+ include MongoMapper::Document
532
+ key :name, String
533
+ end
534
+ Thing.delete_all
535
+ end
536
+
537
+ teardown do
538
+ Object.send :remove_const, 'Property' if defined?(::Property)
539
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
540
+ end
541
+
542
+ context "many" do
543
+ context "=> destroy" do
544
+ setup do
545
+ Property.key :thing_id, String
546
+ Property.belongs_to :thing, :dependent => :destroy
547
+ Thing.many :properties, :dependent => :destroy
548
+
549
+ @thing = Thing.create(:name => "Tree")
550
+ @property1 = Property.create
551
+ @property2 = Property.create
552
+ @property3 = Property.create
553
+ @thing.properties << @property1
554
+ @thing.properties << @property2
555
+ @thing.properties << @property3
556
+ end
557
+
558
+ should "should destroy the associated documents" do
559
+ @thing.properties.count.should == 3
560
+ @thing.destroy
561
+ @thing.properties.count.should == 0
562
+ Property.count.should == 0
563
+ end
564
+ end
565
+
566
+ context "=> delete_all" do
567
+ setup do
568
+ Property.key :thing_id, String
569
+ Property.belongs_to :thing
570
+ Thing.has_many :properties, :dependent => :delete_all
571
+
572
+ @thing = Thing.create(:name => "Tree")
573
+ @property1 = Property.create
574
+ @property2 = Property.create
575
+ @property3 = Property.create
576
+ @thing.properties << @property1
577
+ @thing.properties << @property2
578
+ @thing.properties << @property3
579
+ end
580
+
581
+ should "should delete associated documents" do
582
+ @thing.properties.count.should == 3
583
+ @thing.destroy
584
+ @thing.properties.count.should == 0
585
+ Property.count.should == 0
586
+ end
587
+ end
588
+
589
+ context "=> nullify" do
590
+ setup do
591
+ Property.key :thing_id, String
592
+ Property.belongs_to :thing
593
+ Thing.has_many :properties, :dependent => :nullify
594
+
595
+ @thing = Thing.create(:name => "Tree")
596
+ @property1 = Property.create
597
+ @property2 = Property.create
598
+ @property3 = Property.create
599
+ @thing.properties << @property1
600
+ @thing.properties << @property2
601
+ @thing.properties << @property3
602
+ end
603
+
604
+ should "should nullify relationship but not destroy associated documents" do
605
+ @thing.properties.count.should == 3
606
+ @thing.destroy
607
+ @thing.properties.count.should == 0
608
+ Property.count.should == 3
609
+ end
610
+ end
611
+ end
612
+
613
+ context "belongs_to" do
614
+ context "=> destroy" do
615
+ setup do
616
+ Property.key :thing_id, String
617
+ Property.belongs_to :thing, :dependent => :destroy
618
+ Thing.has_many :properties
619
+
620
+ @thing = Thing.create(:name => "Tree")
621
+ @property1 = Property.create
622
+ @property2 = Property.create
623
+ @property3 = Property.create
624
+ @thing.properties << @property1
625
+ @thing.properties << @property2
626
+ @thing.properties << @property3
627
+ end
628
+
629
+ should "destroy the thing" do
630
+ Thing.count.should == 1
631
+ @property1.destroy
632
+ Thing.count.should == 0
633
+ @property1.thing.should be_frozen
634
+ end
635
+ end
636
+ end
637
+ end
638
+
639
+ context "Counting documents in collection" do
640
+ setup do
641
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
642
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
643
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
644
+ end
645
+
646
+ should "count all with no arguments" do
647
+ @document.count.should == 3
648
+ end
649
+
650
+ should "return 0 if there are no documents in the collection" do
651
+ @document.delete_all
652
+ @document.count.should == 0
653
+ end
654
+
655
+ should "return 0 if the collection does not exist" do
656
+ klass = Class.new do
657
+ include MongoMapper::Document
658
+ set_collection_name 'foobarbazwickdoesnotexist'
659
+ end
660
+
661
+ klass.count.should == 0
662
+ end
663
+
664
+ should "return count for matching documents if conditions provided" do
665
+ @document.count(:age => 27).should == 1
666
+ end
667
+
668
+ should "convert the conditions to mongo criteria" do
669
+ @document.count(:age => [26, 27]).should == 2
670
+ end
671
+ end
672
+
673
+ context "Indexing" do
674
+ setup do
675
+ @document.collection.drop_indexes
676
+ end
677
+
678
+ should "allow creating index for a key" do
679
+ index_name = nil
680
+ lambda {
681
+ index_name = @document.ensure_index :first_name
682
+ }.should change { @document.collection.index_information.size }.by(1)
683
+
684
+ index_name.should == 'first_name_1'
685
+ index = @document.collection.index_information[index_name]
686
+ index.should_not be_nil
687
+ index.should include(['first_name', 1])
688
+ end
689
+
690
+ should "allow creating unique index for a key" do
691
+ @document.collection.expects(:create_index).with(:first_name, true)
692
+ @document.ensure_index :first_name, :unique => true
693
+ end
694
+
695
+ should "allow creating index on multiple keys" do
696
+ index_name = nil
697
+ lambda {
698
+ index_name = @document.ensure_index [[:first_name, 1], [:last_name, -1]]
699
+ }.should change { @document.collection.index_information.size }.by(1)
700
+
701
+ [ 'first_name_1_last_name_-1', 'last_name_-1_first_name_1' ].should include(index_name)
702
+
703
+ index = @document.collection.index_information[index_name]
704
+ index.should_not be_nil
705
+ index.should include(['first_name', 1])
706
+ index.should include(['last_name', -1])
707
+ end
708
+
709
+ should "work with :index shortcut when defining key" do
710
+ @document.expects(:ensure_index).with('father').returns(nil)
711
+ @document.key :father, String, :index => true
712
+ end
713
+ end
714
+ end # Document Class Methods
715
+
716
+ context "Saving a new document" do
717
+ setup do
718
+ @doc = @document.new(:first_name => 'John', :age => '27')
719
+ @doc.save
720
+ end
721
+
722
+ should "insert document into the collection" do
723
+ @document.count.should == 1
724
+ end
725
+
726
+ should "assign an id for the document" do
727
+ @doc.id.should_not be(nil)
728
+ @doc.id.size.should == 24
729
+ end
730
+
731
+ should "save attributes" do
732
+ @doc.first_name.should == 'John'
733
+ @doc.age.should == 27
734
+ end
735
+
736
+ should_eventually "set defaults correctly" do
737
+ @doc.nick_name.should == ""
738
+ end
739
+
740
+ should "update attributes in the database" do
741
+ from_db = @document.find(@doc.id)
742
+ from_db.should == @doc
743
+ from_db.first_name.should == 'John'
744
+ from_db.age.should == 27
745
+ end
746
+
747
+ should "allow to add custom attributes to the document" do
748
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
749
+ @doc.save
750
+ from_db = @document.find(@doc.id)
751
+ from_db.gender.should == 'male'
752
+ from_db.tags.should == [1, "2"]
753
+ end
754
+
755
+ should "allow to use custom methods to assign properties" do
756
+ person = RealPerson.new(:realname => "David")
757
+ person.save
758
+ from_db = RealPerson.find(person.id)
759
+ from_db.name.should == "David"
760
+ end
761
+
762
+ context "with key of type date" do
763
+ should "save the date value as a Time object" do
764
+ doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
765
+ doc.save
766
+ doc.date.should == Date.new(2009, 12, 1)
767
+ end
768
+ end
769
+ end
770
+
771
+ context "Saving an existing document" do
772
+ setup do
773
+ @doc = @document.create(:first_name => 'John', :age => '27')
774
+ @doc.first_name = 'Johnny'
775
+ @doc.age = 30
776
+ @doc.save
777
+ end
778
+
779
+ should "not insert document into collection" do
780
+ @document.count.should == 1
781
+ end
782
+
783
+ should "update attributes" do
784
+ @doc.first_name.should == 'Johnny'
785
+ @doc.age.should == 30
786
+ end
787
+
788
+ should "update attributes in the database" do
789
+ from_db = @document.find(@doc.id)
790
+ from_db.first_name.should == 'Johnny'
791
+ from_db.age.should == 30
792
+ end
793
+
794
+ should "allow updating custom attributes" do
795
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
796
+ @doc.gender = 'Male'
797
+ @doc.save
798
+ from_db = @document.find(@doc.id)
799
+ from_db.gender.should == 'Male'
800
+ end
801
+ end
802
+
803
+ context "Calling update attributes on a new document" do
804
+ setup do
805
+ @doc = @document.new(:first_name => 'John', :age => '27')
806
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
807
+ end
808
+
809
+ should "insert document into the collection" do
810
+ @document.count.should == 1
811
+ end
812
+
813
+ should "assign an id for the document" do
814
+ @doc.id.should_not be(nil)
815
+ @doc.id.size.should == 24
816
+ end
817
+
818
+ should "save attributes" do
819
+ @doc.first_name.should == 'Johnny'
820
+ @doc.age.should == 30
821
+ end
822
+
823
+ should "update attributes in the database" do
824
+ from_db = @document.find(@doc.id)
825
+ from_db.should == @doc
826
+ from_db.first_name.should == 'Johnny'
827
+ from_db.age.should == 30
828
+ end
829
+
830
+ should "allow updating custom attributes" do
831
+ @doc.update_attributes(:gender => 'mALe')
832
+ from_db = @document.find(@doc.id)
833
+ from_db.gender.should == 'mALe'
834
+ end
835
+ end
836
+
837
+ context "Updating an existing document using update attributes" do
838
+ setup do
839
+ @doc = @document.create(:first_name => 'John', :age => '27')
840
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
841
+ end
842
+
843
+ should "not insert document into collection" do
844
+ @document.count.should == 1
845
+ end
846
+
847
+ should "update attributes" do
848
+ @doc.first_name.should == 'Johnny'
849
+ @doc.age.should == 30
850
+ end
851
+
852
+ should "update attributes in the database" do
853
+ from_db = @document.find(@doc.id)
854
+ from_db.first_name.should == 'Johnny'
855
+ from_db.age.should == 30
856
+ end
857
+ end
858
+
859
+ context "update_attributes" do
860
+ setup do
861
+ @document.key :foo, String, :required => true
862
+ end
863
+
864
+ should "return true if document valid" do
865
+ @document.new.update_attributes(:foo => 'bar').should be_true
866
+ end
867
+
868
+ should "return false if document not valid" do
869
+ @document.new.update_attributes({}).should be_false
870
+ end
871
+ end
872
+
873
+ context "Destroying a document that exists" do
874
+ setup do
875
+ @doc = @document.create(:first_name => 'John', :age => '27')
876
+ @doc.destroy
877
+ end
878
+
879
+ should "remove the document from the collection" do
880
+ @document.count.should == 0
881
+ end
882
+
883
+ should "raise error if assignment is attempted" do
884
+ lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
885
+ end
886
+
887
+ should "do nothing if destroy is called again" do
888
+ @doc.destroy.should be_false
889
+ end
890
+ end
891
+
892
+ context "Destroying a document that is a new" do
893
+ setup do
894
+ setup do
895
+ @doc = @document.new(:first_name => 'John Nunemaker', :age => '27')
896
+ @doc.destroy
897
+ end
898
+
899
+ should "not affect collection count" do
900
+ @document.collection.count.should == 0
901
+ end
902
+
903
+ should "raise error if assignment is attempted" do
904
+ lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
905
+ end
906
+ end
907
+ end
908
+
909
+ context "timestamping" do
910
+ setup do
911
+ @document.timestamps!
912
+ end
913
+
914
+ should "set created_at and updated_at on create" do
915
+ doc = @document.new(:first_name => 'John', :age => 27)
916
+ doc.created_at.should be(nil)
917
+ doc.updated_at.should be(nil)
918
+ doc.save
919
+ doc.created_at.should_not be(nil)
920
+ doc.updated_at.should_not be(nil)
921
+ end
922
+
923
+ should "set updated_at on field update but leave created_at alone" do
924
+ doc = @document.create(:first_name => 'John', :age => 27)
925
+ old_created_at = doc.created_at
926
+ old_updated_at = doc.updated_at
927
+ doc.first_name = 'Johnny'
928
+ sleep 1 # this annoys me
929
+ doc.save
930
+ doc.created_at.should == old_created_at
931
+ doc.updated_at.should_not == old_updated_at
932
+ end
933
+
934
+ should "set updated_at on document update but leave created_at alone" do
935
+ doc = @document.create(:first_name => 'John', :age => 27)
936
+ old_created_at = doc.created_at
937
+ old_updated_at = doc.updated_at
938
+ sleep 1 # this annoys me
939
+ @document.update(doc._id, { :first_name => 'Johnny' })
940
+
941
+ from_db = @document.find(doc.id)
942
+ from_db.created_at.to_i.should == old_created_at.to_i
943
+ from_db.updated_at.to_i.should_not == old_updated_at.to_i
944
+ end
945
+ end
946
+ end