novelys_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 +38 -0
  4. data/Rakefile +54 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/lib/mongo_mapper.rb +124 -0
  8. data/lib/mongo_mapper/descendant_appends.rb +44 -0
  9. data/lib/mongo_mapper/document.rb +423 -0
  10. data/lib/mongo_mapper/dynamic_finder.rb +74 -0
  11. data/lib/mongo_mapper/embedded_document.rb +67 -0
  12. data/lib/mongo_mapper/finder_options.rb +127 -0
  13. data/lib/mongo_mapper/plugins.rb +14 -0
  14. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  15. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  16. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  17. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  18. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  19. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  20. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  21. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  22. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  23. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  24. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  25. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  26. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  27. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  28. data/lib/mongo_mapper/plugins/callbacks.rb +76 -0
  29. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  30. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  31. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  32. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  33. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  34. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  35. data/lib/mongo_mapper/plugins/keys.rb +300 -0
  36. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  37. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  38. data/lib/mongo_mapper/plugins/protected.rb +41 -0
  39. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  40. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  41. data/lib/mongo_mapper/plugins/validations.rb +62 -0
  42. data/lib/mongo_mapper/support.rb +214 -0
  43. data/mongo_mapper.gemspec +179 -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 +1245 -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 +139 -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 +55 -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 +125 -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 +248 -0
@@ -0,0 +1,1245 @@
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 "find_or_create" do
411
+ should "find if exists" do
412
+ created = @document.create(:first_name => 'John', :last_name => 'Nunemaker')
413
+ lambda {
414
+ found = @document.find_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.find_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 "ClassMethods#delete (single document)" do
429
+ setup do
430
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
431
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
432
+ @document.delete(@doc1._id)
433
+ end
434
+
435
+ should "remove document from collection" do
436
+ @document.count.should == 1
437
+ end
438
+
439
+ should "not remove other documents" do
440
+ @document.find(@doc2._id).should_not be(nil)
441
+ end
442
+ end
443
+
444
+ context "ClassMethods#delete (multiple documents)" do
445
+ should "work with multiple arguments" 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
+
454
+ should "work with array as argument" do
455
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
456
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
457
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
458
+ @document.delete([@doc1._id, @doc2._id])
459
+
460
+ @document.count.should == 1
461
+ end
462
+ end
463
+
464
+ context "ClassMethods#delete_all" do
465
+ setup do
466
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
467
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
468
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
469
+ end
470
+
471
+ should "remove all documents when given no conditions" do
472
+ @document.delete_all
473
+ @document.count.should == 0
474
+ end
475
+
476
+ should "only remove matching documents when given conditions" do
477
+ @document.delete_all({:first_name => 'John'})
478
+ @document.count.should == 2
479
+ end
480
+
481
+ should "convert the conditions to mongo criteria" do
482
+ @document.delete_all(:age => [26, 27])
483
+ @document.count.should == 1
484
+ end
485
+ end
486
+
487
+ context "ClassMethods#destroy (single document)" do
488
+ setup do
489
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
490
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
491
+ @document.destroy(@doc1._id)
492
+ end
493
+
494
+ should "remove document from collection" do
495
+ @document.count.should == 1
496
+ end
497
+
498
+ should "not remove other documents" do
499
+ @document.find(@doc2._id).should_not be(nil)
500
+ end
501
+ end
502
+
503
+ context "ClassMethods#destroy (multiple documents)" do
504
+ should "work with multiple arguments" 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
+
513
+ should "work with array as argument" do
514
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
515
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
516
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
517
+ @document.destroy([@doc1._id, @doc2._id])
518
+
519
+ @document.count.should == 1
520
+ end
521
+ end
522
+
523
+ context "ClassMethods#destroy_all" do
524
+ setup do
525
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
526
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
527
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
528
+ end
529
+
530
+ should "remove all documents when given no conditions" do
531
+ @document.destroy_all
532
+ @document.count.should == 0
533
+ end
534
+
535
+ should "only remove matching documents when given conditions" do
536
+ @document.destroy_all(:first_name => 'John')
537
+ @document.count.should == 2
538
+ @document.destroy_all(:age => 26)
539
+ @document.count.should == 1
540
+ end
541
+
542
+ should "convert the conditions to mongo criteria" do
543
+ @document.destroy_all(:age => [26, 27])
544
+ @document.count.should == 1
545
+ end
546
+ end
547
+
548
+ context "ClassMethods#count" do
549
+ setup do
550
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
551
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
552
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
553
+ end
554
+
555
+ should "count all with no arguments" do
556
+ @document.count.should == 3
557
+ end
558
+
559
+ should "return 0 if there are no documents in the collection" do
560
+ @document.delete_all
561
+ @document.count.should == 0
562
+ end
563
+
564
+ should "return 0 if the collection does not exist" do
565
+ klass = Doc do
566
+ set_collection_name 'foobarbazwickdoesnotexist'
567
+ end
568
+
569
+ klass.count.should == 0
570
+ end
571
+
572
+ should "return count for matching documents if conditions provided" do
573
+ @document.count(:age => 27).should == 1
574
+ end
575
+
576
+ should "convert the conditions to mongo criteria" do
577
+ @document.count(:age => [26, 27]).should == 2
578
+ end
579
+ end
580
+
581
+ should "have instance method for collection" do
582
+ @document.new.collection.name.should == @document.collection.name
583
+ end
584
+
585
+ should "have instance method for database" do
586
+ @document.new.database.should == @document.database
587
+ end
588
+
589
+ context "#update_attributes (new document)" do
590
+ setup do
591
+ @doc = @document.new(:first_name => 'John', :age => '27')
592
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
593
+ end
594
+
595
+ should "insert document into the collection" do
596
+ @document.count.should == 1
597
+ end
598
+
599
+ should "assign an id for the document" do
600
+ @doc.id.should be_instance_of(Mongo::ObjectID)
601
+ end
602
+
603
+ should "save attributes" do
604
+ @doc.first_name.should == 'Johnny'
605
+ @doc.age.should == 30
606
+ end
607
+
608
+ should "update attributes in the database" do
609
+ doc = @doc.reload
610
+ doc.should == @doc
611
+ doc.first_name.should == 'Johnny'
612
+ doc.age.should == 30
613
+ end
614
+
615
+ should "allow updating custom attributes" do
616
+ @doc.update_attributes(:gender => 'mALe')
617
+ @doc.reload.gender.should == 'mALe'
618
+ end
619
+ end
620
+
621
+ context "#update_attributes (existing document)" do
622
+ setup do
623
+ @doc = @document.create(:first_name => 'John', :age => '27')
624
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
625
+ end
626
+
627
+ should "not insert document into collection" do
628
+ @document.count.should == 1
629
+ end
630
+
631
+ should "update attributes" do
632
+ @doc.first_name.should == 'Johnny'
633
+ @doc.age.should == 30
634
+ end
635
+
636
+ should "update attributes in the database" do
637
+ doc = @doc.reload
638
+ doc.first_name.should == 'Johnny'
639
+ doc.age.should == 30
640
+ end
641
+ end
642
+
643
+ context "#update_attributes (return value)" do
644
+ setup do
645
+ @document.key :foo, String, :required => true
646
+ end
647
+
648
+ should "be true if document valid" do
649
+ @document.new.update_attributes(:foo => 'bar').should be_true
650
+ end
651
+
652
+ should "be false if document not valid" do
653
+ @document.new.update_attributes({}).should be_false
654
+ end
655
+ end
656
+
657
+ context "#save (new document)" do
658
+ setup do
659
+ @doc = @document.new(:first_name => 'John', :age => '27')
660
+ @doc.save
661
+ end
662
+
663
+ should "insert document into the collection" do
664
+ @document.count.should == 1
665
+ end
666
+
667
+ should "assign an id for the document" do
668
+ @doc.id.should be_instance_of(Mongo::ObjectID)
669
+ end
670
+
671
+ should "save attributes" do
672
+ @doc.first_name.should == 'John'
673
+ @doc.age.should == 27
674
+ end
675
+
676
+ should "update attributes in the database" do
677
+ doc = @doc.reload
678
+ doc.should == @doc
679
+ doc.first_name.should == 'John'
680
+ doc.age.should == 27
681
+ end
682
+
683
+ should "allow to add custom attributes to the document" do
684
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
685
+ @doc.save
686
+ doc = @doc.reload
687
+ doc.gender.should == 'male'
688
+ doc.tags.should == [1, "2"]
689
+ end
690
+
691
+ should "allow to use custom methods to assign properties" do
692
+ klass = Doc do
693
+ key :name, String
694
+
695
+ def realname=(value)
696
+ self.name = value
697
+ end
698
+ end
699
+
700
+ person = klass.new(:realname => 'David')
701
+ person.save
702
+ person.reload.name.should == 'David'
703
+ end
704
+
705
+ context "with key of type date" do
706
+ should "save the date value as a Time object" do
707
+ doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
708
+ doc.save
709
+ doc.date.should == Date.new(2009, 12, 1)
710
+ end
711
+ end
712
+ end
713
+
714
+ context "#save (existing document)" do
715
+ setup do
716
+ @doc = @document.create(:first_name => 'John', :age => '27')
717
+ @doc.first_name = 'Johnny'
718
+ @doc.age = 30
719
+ @doc.save
720
+ end
721
+
722
+ should "not insert document into collection" do
723
+ @document.count.should == 1
724
+ end
725
+
726
+ should "update attributes" do
727
+ @doc.first_name.should == 'Johnny'
728
+ @doc.age.should == 30
729
+ end
730
+
731
+ should "update attributes in the database" do
732
+ doc = @doc.reload
733
+ doc.first_name.should == 'Johnny'
734
+ doc.age.should == 30
735
+ end
736
+
737
+ should "allow updating custom attributes" do
738
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
739
+ @doc.gender = 'Male'
740
+ @doc.save
741
+ @doc.reload.gender.should == 'Male'
742
+ end
743
+ end
744
+
745
+ context "#save (with validations off)" do
746
+ setup do
747
+ @document = Doc do
748
+ key :name, String, :required => true
749
+ end
750
+ end
751
+
752
+ should "insert invalid document" do
753
+ doc = @document.new
754
+ doc.expects(:valid?).never
755
+ doc.save(:validate => false)
756
+ @document.count.should == 1
757
+ end
758
+ end
759
+
760
+ context "#save (with options)" do
761
+ setup do
762
+ MongoMapper.ensured_indexes = []
763
+
764
+ @document = Doc do
765
+ key :name, String
766
+ set_collection_name 'test_indexes'
767
+ ensure_index :name, :unique => true
768
+ end
769
+ if @document.database.collection_names.include?(@document.collection.name)
770
+ @document.collection.drop_indexes
771
+ end
772
+
773
+ MongoMapper.ensure_indexes!
774
+ end
775
+
776
+ should "allow passing safe" do
777
+ doc = @document.new(:name => 'John')
778
+ doc.save
779
+
780
+ assert_raises(Mongo::OperationFailure) do
781
+ @document.new(:name => 'John').save(:safe => true)
782
+ end
783
+ end
784
+
785
+ should "raise argument error if options has unsupported key" do
786
+ doc = @document.new
787
+ assert_raises(ArgumentError) { doc.save(:foo => true) }
788
+ end
789
+ end
790
+
791
+ context "#save! (with options)" do
792
+ setup do
793
+ MongoMapper.ensured_indexes = []
794
+
795
+ @document = Doc do
796
+ key :name, String
797
+ set_collection_name 'test_indexes'
798
+ ensure_index :name, :unique => true
799
+ end
800
+
801
+ if @document.database.collection_names.include?(@document.collection.name)
802
+ @document.collection.drop_indexes
803
+ end
804
+
805
+ MongoMapper.ensure_indexes!
806
+ end
807
+
808
+ should "allow passing safe" do
809
+ doc = @document.create(:name => 'John')
810
+
811
+ assert_raises(Mongo::OperationFailure) do
812
+ @document.new(:name => 'John').save!(:safe => true)
813
+ end
814
+ end
815
+
816
+ should "raise argument error if options has unsupported key" do
817
+ doc = @document.new
818
+ assert_raises(ArgumentError) { doc.save!(:foo => true) }
819
+ end
820
+
821
+ should "raise argument error if using validate as that would be pointless with save!" do
822
+ doc = @document.new
823
+ assert_raises(ArgumentError) { doc.save!(:validate => false) }
824
+ end
825
+ end
826
+
827
+ context "#destroy" do
828
+ setup do
829
+ @doc = @document.create(:first_name => 'John', :age => '27')
830
+ @doc.destroy
831
+ end
832
+
833
+ should "remove the document from the collection" do
834
+ @document.count.should == 0
835
+ end
836
+ end
837
+
838
+ context "#delete" do
839
+ setup do
840
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
841
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
842
+
843
+ @document.class_eval do
844
+ before_destroy :before_destroy_callback
845
+ after_destroy :after_destroy_callback
846
+
847
+ def history; @history ||= [] end
848
+ def before_destroy_callback; history << :after_destroy end
849
+ def after_destroy_callback; history << :after_destroy end
850
+ end
851
+
852
+ @doc1.delete
853
+ end
854
+
855
+ should "remove document from collection" do
856
+ @document.count.should == 1
857
+ end
858
+
859
+ should "not remove other documents" do
860
+ @document.find(@doc2.id).should_not be(nil)
861
+ end
862
+
863
+ should "not call before/after destroy callbacks" do
864
+ @doc1.history.should == []
865
+ end
866
+ end
867
+
868
+ context "Single collection inheritance" do
869
+ setup do
870
+ class ::DocParent
871
+ include MongoMapper::Document
872
+ key :_type, String
873
+ key :name, String
874
+ end
875
+ DocParent.collection.remove
876
+
877
+ class ::DocDaughter < ::DocParent; end
878
+ class ::DocSon < ::DocParent; end
879
+ class ::DocGrandSon < ::DocSon; end
880
+
881
+ DocSon.many :children, :class_name => 'DocGrandSon'
882
+
883
+ @parent = DocParent.new({:name => "Daddy Warbucks"})
884
+ @daughter = DocDaughter.new({:name => "Little Orphan Annie"})
885
+ end
886
+
887
+ teardown do
888
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
889
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
890
+ Object.send :remove_const, 'DocSon' if defined?(::DocSon)
891
+ Object.send :remove_const, 'DocGrandSon' if defined?(::DocGrandSon)
892
+ end
893
+
894
+ should "use the same collection in the subclass" do
895
+ DocDaughter.collection.name.should == DocParent.collection.name
896
+ end
897
+
898
+ should "assign the class name into the _type property" do
899
+ @parent._type.should == 'DocParent'
900
+ @daughter._type.should == 'DocDaughter'
901
+ end
902
+
903
+ should "load the document with the assigned type" do
904
+ @parent.save
905
+ @daughter.save
906
+
907
+ collection = DocParent.all
908
+ collection.size.should == 2
909
+ collection.first.should be_kind_of(DocParent)
910
+ collection.first.name.should == "Daddy Warbucks"
911
+ collection.last.should be_kind_of(DocDaughter)
912
+ collection.last.name.should == "Little Orphan Annie"
913
+ end
914
+
915
+ should "gracefully handle when the type can't be constantized" do
916
+ doc = DocParent.new(:name => 'Nunes')
917
+ doc._type = 'FoobarBaz'
918
+ doc.save
919
+
920
+ collection = DocParent.all
921
+ collection.last.should == doc
922
+ collection.last.should be_kind_of(DocParent)
923
+ end
924
+
925
+ should "find scoped to class" do
926
+ john = DocSon.create(:name => 'John')
927
+ steve = DocSon.create(:name => 'Steve')
928
+ steph = DocDaughter.create(:name => 'Steph')
929
+ carrie = DocDaughter.create(:name => 'Carrie')
930
+
931
+ DocGrandSon.all(:order => 'name').should == []
932
+ DocSon.all(:order => 'name').should == [john, steve]
933
+ DocDaughter.all(:order => 'name').should == [carrie, steph]
934
+ DocParent.all(:order => 'name').should == [carrie, john, steph, steve]
935
+ end
936
+
937
+ should "work with nested hash conditions" do
938
+ john = DocSon.create(:name => 'John')
939
+ steve = DocSon.create(:name => 'Steve')
940
+ DocSon.all(:name => {'$ne' => 'Steve'}).should == [john]
941
+ end
942
+
943
+ should "raise error if not found scoped to class" do
944
+ john = DocSon.create(:name => 'John')
945
+ steph = DocDaughter.create(:name => 'Steph')
946
+
947
+ lambda {
948
+ DocSon.find!(steph._id)
949
+ }.should raise_error(MongoMapper::DocumentNotFound)
950
+ end
951
+
952
+ should "not raise error for find with parent" do
953
+ john = DocSon.create(:name => 'John')
954
+
955
+ DocParent.find!(john._id).should == john
956
+ end
957
+
958
+ should "count scoped to class" do
959
+ john = DocSon.create(:name => 'John')
960
+ steve = DocSon.create(:name => 'Steve')
961
+ steph = DocDaughter.create(:name => 'Steph')
962
+ carrie = DocDaughter.create(:name => 'Carrie')
963
+
964
+ DocGrandSon.count.should == 0
965
+ DocSon.count.should == 2
966
+ DocDaughter.count.should == 2
967
+ DocParent.count.should == 4
968
+ end
969
+
970
+ should "know if it is single_collection_inherited?" do
971
+ DocParent.single_collection_inherited?.should be_false
972
+
973
+ DocDaughter.single_collection_inherited?.should be_true
974
+ DocSon.single_collection_inherited?.should be_true
975
+ end
976
+
977
+ should "know if single_collection_inherited_superclass?" do
978
+ DocParent.single_collection_inherited_superclass?.should be_false
979
+
980
+ DocDaughter.single_collection_inherited_superclass?.should be_true
981
+ DocSon.single_collection_inherited_superclass?.should be_true
982
+ DocGrandSon.single_collection_inherited_superclass?.should be_true
983
+ end
984
+
985
+ should "not be able to destroy each other" do
986
+ john = DocSon.create(:name => 'John')
987
+ steph = DocDaughter.create(:name => 'Steph')
988
+
989
+ lambda {
990
+ DocSon.destroy(steph._id)
991
+ }.should raise_error(MongoMapper::DocumentNotFound)
992
+ end
993
+
994
+ should "not be able to delete each other" do
995
+ john = DocSon.create(:name => 'John')
996
+ steph = DocDaughter.create(:name => 'Steph')
997
+
998
+ lambda {
999
+ DocSon.delete(steph._id)
1000
+ }.should_not change { DocParent.count }
1001
+ end
1002
+
1003
+ should "be able to destroy using parent" do
1004
+ john = DocSon.create(:name => 'John')
1005
+ steph = DocDaughter.create(:name => 'Steph')
1006
+
1007
+ lambda {
1008
+ DocParent.destroy_all
1009
+ }.should change { DocParent.count }.by(-2)
1010
+ end
1011
+
1012
+ should "be able to delete using parent" do
1013
+ john = DocSon.create(:name => 'John')
1014
+ steph = DocDaughter.create(:name => 'Steph')
1015
+
1016
+ lambda {
1017
+ DocParent.delete_all
1018
+ }.should change { DocParent.count }.by(-2)
1019
+ end
1020
+
1021
+ should "be able to reload parent inherited class" do
1022
+ brian = DocParent.create(:name => 'Brian')
1023
+ brian.name = 'B-Dawg'
1024
+ brian.reload
1025
+ brian.name.should == 'Brian'
1026
+ end
1027
+ end
1028
+
1029
+ context "timestamping" do
1030
+ setup do
1031
+ @klass = Doc do
1032
+ set_collection_name 'users'
1033
+
1034
+ key :first_name, String
1035
+ key :last_name, String
1036
+ key :age, Integer
1037
+ key :date, Date
1038
+ end
1039
+ @klass.timestamps!
1040
+ end
1041
+
1042
+ should "set created_at and updated_at on create" do
1043
+ doc = @klass.new(:first_name => 'John', :age => 27)
1044
+ doc.created_at.should be(nil)
1045
+ doc.updated_at.should be(nil)
1046
+ doc.save
1047
+ doc.created_at.should_not be(nil)
1048
+ doc.updated_at.should_not be(nil)
1049
+ end
1050
+
1051
+ should "not overwrite created_at if it already exists" do
1052
+ original_created_at = 1.month.ago
1053
+ doc = @klass.new(:first_name => 'John', :age => 27, :created_at => original_created_at)
1054
+ doc.created_at.to_i.should == original_created_at.to_i
1055
+ doc.updated_at.should be_nil
1056
+ doc.save
1057
+ doc.created_at.to_i.should == original_created_at.to_i
1058
+ doc.updated_at.should_not be_nil
1059
+ end
1060
+
1061
+ should "set updated_at on field update but leave created_at alone" do
1062
+ doc = @klass.create(:first_name => 'John', :age => 27)
1063
+ old_created_at = doc.created_at
1064
+ old_updated_at = doc.updated_at
1065
+ doc.first_name = 'Johnny'
1066
+
1067
+ Timecop.freeze(Time.now + 5.seconds) do
1068
+ doc.save
1069
+ end
1070
+
1071
+ doc.created_at.should == old_created_at
1072
+ doc.updated_at.should_not == old_updated_at
1073
+ end
1074
+
1075
+ should "set updated_at on document update but leave created_at alone" do
1076
+ doc = @klass.create(:first_name => 'John', :age => 27)
1077
+ old_created_at = doc.created_at
1078
+ old_updated_at = doc.updated_at
1079
+
1080
+ Timecop.freeze(Time.now + 5.seconds) do
1081
+ @klass.update(doc._id, { :first_name => 'Johnny' })
1082
+ end
1083
+
1084
+ doc = doc.reload
1085
+ doc.created_at.should == old_created_at
1086
+ doc.updated_at.should_not == old_updated_at
1087
+ end
1088
+ end
1089
+
1090
+ context "userstamping" do
1091
+ setup do
1092
+ @document.userstamps!
1093
+ end
1094
+
1095
+ should "add creator_id key" do
1096
+ @document.keys.keys.should include('creator_id')
1097
+ end
1098
+
1099
+ should "add updater_id key" do
1100
+ @document.keys.keys.should include('updater_id')
1101
+ end
1102
+
1103
+ should "add belongs_to creator" do
1104
+ @document.associations.keys.should include('creator')
1105
+ end
1106
+
1107
+ should "add belongs_to updater" do
1108
+ @document.associations.keys.should include('updater')
1109
+ end
1110
+ end
1111
+
1112
+ context "#exists?" do
1113
+ setup do
1114
+ @doc = @document.create(:first_name => "James", :age => 27)
1115
+ end
1116
+
1117
+ should "be true when at least one document exists" do
1118
+ @document.exists?.should == true
1119
+ end
1120
+
1121
+ should "be false when no documents exist" do
1122
+ @doc.destroy
1123
+ @document.exists?.should == false
1124
+ end
1125
+
1126
+ should "be true when at least one document exists that matches the conditions" do
1127
+ @document.exists?(:first_name => "James").should == true
1128
+ end
1129
+
1130
+ should "be false when no documents exist with the provided conditions" do
1131
+ @document.exists?(:first_name => "Jean").should == false
1132
+ end
1133
+ end
1134
+
1135
+ context "#reload" do
1136
+ setup do
1137
+ @foo_class = Doc do
1138
+ key :name
1139
+ end
1140
+
1141
+ @bar_class = EDoc do
1142
+ key :name
1143
+ end
1144
+
1145
+ @document.many :foos, :class => @foo_class
1146
+ @document.many :bars, :class => @bar_class
1147
+
1148
+ @instance = @document.create({
1149
+ :age => 39,
1150
+ :foos => [@foo_class.new(:name => '1')],
1151
+ :bars => [@bar_class.new(:name => '1')],
1152
+ })
1153
+ end
1154
+
1155
+ should "reload keys from the database" do
1156
+ @instance.age = 37
1157
+ @instance.age.should == 37
1158
+ @instance.reload
1159
+ @instance.age.should == 39
1160
+ end
1161
+
1162
+ should "reset all associations" do
1163
+ @instance.foos.expects(:reset).at_least_once
1164
+ @instance.bars.expects(:reset).at_least_once
1165
+ @instance.reload
1166
+ end
1167
+
1168
+ should "reinstantiate embedded associations" do
1169
+ @instance.reload
1170
+ @instance.bars.first.name.should == '1'
1171
+ end
1172
+
1173
+ should "return self" do
1174
+ @instance.reload.object_id.should == @instance.object_id
1175
+ end
1176
+
1177
+ should "raise DocumentNotFound if not found" do
1178
+ @instance.destroy
1179
+ assert_raises(MongoMapper::DocumentNotFound) { @instance.reload }
1180
+ end
1181
+ end
1182
+
1183
+ context "database has keys not defined in model" do
1184
+ setup do
1185
+ @id = Mongo::ObjectID.new
1186
+ @document.collection.insert({
1187
+ :_id => @id,
1188
+ :first_name => 'John',
1189
+ :last_name => 'Nunemaker',
1190
+ :age => 27,
1191
+ :favorite_color => 'red',
1192
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
1193
+ })
1194
+ end
1195
+
1196
+ should "assign all keys from database" do
1197
+ doc = @document.find(@id)
1198
+ doc.first_name.should == 'John'
1199
+ doc.last_name.should == 'Nunemaker'
1200
+ doc.age.should == 27
1201
+ doc.favorite_color.should == 'red'
1202
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
1203
+ end
1204
+ end
1205
+
1206
+ context "Indexing" do
1207
+ setup do
1208
+ MongoMapper.ensured_indexes = []
1209
+ @document.collection.drop_indexes
1210
+ end
1211
+
1212
+ should "allow creating index for a key" do
1213
+ @document.ensure_index :first_name
1214
+ MongoMapper.ensure_indexes!
1215
+
1216
+ @document.should have_index('first_name_1')
1217
+ end
1218
+
1219
+ should "allow creating unique index for a key" do
1220
+ @document.ensure_index :first_name, :unique => true
1221
+ MongoMapper.ensure_indexes!
1222
+
1223
+ @document.should have_index('first_name_1')
1224
+ end
1225
+
1226
+ should "allow creating index on multiple keys" do
1227
+ @document.ensure_index [[:first_name, 1], [:last_name, -1]]
1228
+ MongoMapper.ensure_indexes!
1229
+
1230
+ # order is different for different versions of ruby so instead of
1231
+ # just checking have_index('first_name_1_last_name_-1') I'm checking
1232
+ # the values of the indexes to make sure the index creation was successful
1233
+ @document.collection.index_information.detect do |index|
1234
+ keys = index[1]
1235
+ keys.include?(['first_name', 1]) && keys.include?(['last_name', -1])
1236
+ end.should_not be_nil
1237
+ end
1238
+
1239
+ should "work with :index shortcut when defining key" do
1240
+ @document.key :father, String, :index => true
1241
+ MongoMapper.ensure_indexes!
1242
+ @document.should have_index('father_1')
1243
+ end
1244
+ end
1245
+ end