drogus-mongo_mapper 0.6.10

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