djsun-mongo_mapper 0.5.0.1

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