djsun-mongomapper 0.3.5.5 → 0.4.1.2

Sign up to get free protection for your applications and to get access to all the features.
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