djsun-mongo_mapper 0.5.0.1

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