mongo_mapper-rails3 0.7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/.gitignore +10 -0
  2. data/Gemfile +15 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +60 -0
  5. data/Rakefile +58 -0
  6. data/VERSION +1 -0
  7. data/bin/mmconsole +60 -0
  8. data/lib/mongo_mapper.rb +131 -0
  9. data/lib/mongo_mapper/document.rb +439 -0
  10. data/lib/mongo_mapper/embedded_document.rb +68 -0
  11. data/lib/mongo_mapper/plugins.rb +30 -0
  12. data/lib/mongo_mapper/plugins/associations.rb +106 -0
  13. data/lib/mongo_mapper/plugins/associations/base.rb +123 -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 +141 -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 +120 -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 +119 -0
  26. data/lib/mongo_mapper/plugins/callbacks.rb +87 -0
  27. data/lib/mongo_mapper/plugins/clone.rb +14 -0
  28. data/lib/mongo_mapper/plugins/descendants.rb +17 -0
  29. data/lib/mongo_mapper/plugins/dirty.rb +120 -0
  30. data/lib/mongo_mapper/plugins/equality.rb +24 -0
  31. data/lib/mongo_mapper/plugins/identity_map.rb +124 -0
  32. data/lib/mongo_mapper/plugins/inspect.rb +15 -0
  33. data/lib/mongo_mapper/plugins/keys.rb +310 -0
  34. data/lib/mongo_mapper/plugins/logger.rb +19 -0
  35. data/lib/mongo_mapper/plugins/pagination.rb +26 -0
  36. data/lib/mongo_mapper/plugins/pagination/proxy.rb +72 -0
  37. data/lib/mongo_mapper/plugins/protected.rb +46 -0
  38. data/lib/mongo_mapper/plugins/rails.rb +46 -0
  39. data/lib/mongo_mapper/plugins/serialization.rb +50 -0
  40. data/lib/mongo_mapper/plugins/validations.rb +88 -0
  41. data/lib/mongo_mapper/query.rb +130 -0
  42. data/lib/mongo_mapper/support.rb +217 -0
  43. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  44. data/lib/mongo_mapper/support/find.rb +77 -0
  45. data/mongo_mapper-rails3.gemspec +208 -0
  46. data/performance/read_write.rb +52 -0
  47. data/specs.watchr +51 -0
  48. data/test/NOTE_ON_TESTING +1 -0
  49. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  50. data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
  51. data/test/functional/associations/test_in_array_proxy.rb +321 -0
  52. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  53. data/test/functional/associations/test_many_documents_proxy.rb +453 -0
  54. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  55. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  56. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  57. data/test/functional/associations/test_one_proxy.rb +161 -0
  58. data/test/functional/test_associations.rb +44 -0
  59. data/test/functional/test_binary.rb +27 -0
  60. data/test/functional/test_callbacks.rb +81 -0
  61. data/test/functional/test_dirty.rb +163 -0
  62. data/test/functional/test_document.rb +1244 -0
  63. data/test/functional/test_embedded_document.rb +125 -0
  64. data/test/functional/test_identity_map.rb +508 -0
  65. data/test/functional/test_logger.rb +20 -0
  66. data/test/functional/test_modifiers.rb +252 -0
  67. data/test/functional/test_pagination.rb +93 -0
  68. data/test/functional/test_protected.rb +161 -0
  69. data/test/functional/test_string_id_compatibility.rb +67 -0
  70. data/test/functional/test_validations.rb +329 -0
  71. data/test/models.rb +232 -0
  72. data/test/support/custom_matchers.rb +55 -0
  73. data/test/support/timing.rb +16 -0
  74. data/test/test_helper.rb +59 -0
  75. data/test/unit/associations/test_base.rb +207 -0
  76. data/test/unit/associations/test_proxy.rb +105 -0
  77. data/test/unit/serializers/test_json_serializer.rb +189 -0
  78. data/test/unit/test_descendant_appends.rb +71 -0
  79. data/test/unit/test_document.rb +231 -0
  80. data/test/unit/test_dynamic_finder.rb +123 -0
  81. data/test/unit/test_embedded_document.rb +663 -0
  82. data/test/unit/test_keys.rb +169 -0
  83. data/test/unit/test_lint.rb +8 -0
  84. data/test/unit/test_mongo_mapper.rb +125 -0
  85. data/test/unit/test_pagination.rb +160 -0
  86. data/test/unit/test_plugins.rb +51 -0
  87. data/test/unit/test_query.rb +334 -0
  88. data/test/unit/test_rails.rb +123 -0
  89. data/test/unit/test_rails_compatibility.rb +57 -0
  90. data/test/unit/test_serialization.rb +51 -0
  91. data/test/unit/test_support.rb +362 -0
  92. data/test/unit/test_time_zones.rb +39 -0
  93. data/test/unit/test_validations.rb +557 -0
  94. metadata +344 -0
@@ -0,0 +1,1244 @@
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
+ @document = Doc do
782
+ key :name, String
783
+ set_collection_name 'test_indexes'
784
+ end
785
+ drop_indexes(@document)
786
+ @document.ensure_index :name, :unique => true
787
+ end
788
+
789
+ should "allow passing safe" do
790
+ @document.create(:name => 'John')
791
+ assert_raises(Mongo::OperationFailure) do
792
+ @document.new(:name => 'John').save(:safe => true)
793
+ end
794
+ end
795
+
796
+ should "raise argument error if options has unsupported key" do
797
+ assert_raises(ArgumentError) do
798
+ @document.new.save(:foo => true)
799
+ end
800
+ end
801
+ end
802
+
803
+ context "#save! (with options)" do
804
+ setup do
805
+ @document = Doc do
806
+ key :name, String
807
+ set_collection_name 'test_indexes'
808
+ end
809
+ drop_indexes(@document)
810
+ @document.ensure_index :name, :unique => true
811
+ end
812
+
813
+ should "allow passing safe" do
814
+ @document.create(:name => 'John')
815
+ assert_raises(Mongo::OperationFailure) do
816
+ @document.new(:name => 'John').save!(:safe => true)
817
+ end
818
+ end
819
+
820
+ should "raise argument error if options has unsupported key" do
821
+ assert_raises(ArgumentError) do
822
+ @document.new.save!(:foo => true)
823
+ end
824
+ end
825
+
826
+ should "raise argument error if using validate as that would be pointless with save!" do
827
+ assert_raises(ArgumentError) do
828
+ @document.new.save!(:validate => false)
829
+ end
830
+ end
831
+ end
832
+
833
+ context "#destroy" do
834
+ setup do
835
+ @doc = @document.create(:first_name => 'John', :age => '27')
836
+ @doc.destroy
837
+ end
838
+
839
+ should "remove the document from the collection" do
840
+ @document.count.should == 0
841
+ end
842
+ end
843
+
844
+ context "#delete" do
845
+ setup do
846
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
847
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
848
+
849
+ @document.class_eval do
850
+ before_destroy :before_destroy_callback
851
+ after_destroy :after_destroy_callback
852
+
853
+ def history; @history ||= [] end
854
+ def before_destroy_callback; history << :after_destroy end
855
+ def after_destroy_callback; history << :after_destroy end
856
+ end
857
+
858
+ @doc1.delete
859
+ end
860
+
861
+ should "remove document from collection" do
862
+ @document.count.should == 1
863
+ end
864
+
865
+ should "not remove other documents" do
866
+ @document.find(@doc2.id).should_not be(nil)
867
+ end
868
+
869
+ should "not call before/after destroy callbacks" do
870
+ @doc1.history.should == []
871
+ end
872
+ end
873
+
874
+ context "Single collection inheritance" do
875
+ setup do
876
+ class ::DocParent
877
+ include MongoMapper::Document
878
+ key :_type, String
879
+ key :name, String
880
+ end
881
+ DocParent.collection.remove
882
+
883
+ class ::DocDaughter < ::DocParent; end
884
+ class ::DocSon < ::DocParent; end
885
+ class ::DocGrandSon < ::DocSon; end
886
+
887
+ DocSon.many :children, :class_name => 'DocGrandSon'
888
+
889
+ @parent = DocParent.new({:name => "Daddy Warbucks"})
890
+ @daughter = DocDaughter.new({:name => "Little Orphan Annie"})
891
+ end
892
+
893
+ teardown do
894
+ Object.send :remove_const, 'DocParent' if defined?(::DocParent)
895
+ Object.send :remove_const, 'DocDaughter' if defined?(::DocDaughter)
896
+ Object.send :remove_const, 'DocSon' if defined?(::DocSon)
897
+ Object.send :remove_const, 'DocGrandSon' if defined?(::DocGrandSon)
898
+ end
899
+
900
+ should "use the same collection in the subclass" do
901
+ DocDaughter.collection.name.should == DocParent.collection.name
902
+ end
903
+
904
+ should "assign the class name into the _type property" do
905
+ @parent._type.should == 'DocParent'
906
+ @daughter._type.should == 'DocDaughter'
907
+ end
908
+
909
+ should "load the document with the assigned type" do
910
+ @parent.save
911
+ @daughter.save
912
+
913
+ collection = DocParent.all
914
+ collection.size.should == 2
915
+ collection.first.should be_kind_of(DocParent)
916
+ collection.first.name.should == "Daddy Warbucks"
917
+ collection.last.should be_kind_of(DocDaughter)
918
+ collection.last.name.should == "Little Orphan Annie"
919
+ end
920
+
921
+ should "gracefully handle when the type can't be constantized" do
922
+ doc = DocParent.new(:name => 'Nunes')
923
+ doc._type = 'FoobarBaz'
924
+ doc.save
925
+
926
+ collection = DocParent.all
927
+ collection.last.should == doc
928
+ collection.last.should be_kind_of(DocParent)
929
+ end
930
+
931
+ should "find scoped to class" do
932
+ john = DocSon.create(:name => 'John')
933
+ steve = DocSon.create(:name => 'Steve')
934
+ steph = DocDaughter.create(:name => 'Steph')
935
+ carrie = DocDaughter.create(:name => 'Carrie')
936
+
937
+ DocGrandSon.all(:order => 'name').should == []
938
+ DocSon.all(:order => 'name').should == [john, steve]
939
+ DocDaughter.all(:order => 'name').should == [carrie, steph]
940
+ DocParent.all(:order => 'name').should == [carrie, john, steph, steve]
941
+ end
942
+
943
+ should "work with nested hash conditions" do
944
+ john = DocSon.create(:name => 'John')
945
+ steve = DocSon.create(:name => 'Steve')
946
+ DocSon.all(:name => {'$ne' => 'Steve'}).should == [john]
947
+ end
948
+
949
+ should "raise error if not found scoped to class" do
950
+ john = DocSon.create(:name => 'John')
951
+ steph = DocDaughter.create(:name => 'Steph')
952
+
953
+ lambda {
954
+ DocSon.find!(steph._id)
955
+ }.should raise_error(MongoMapper::DocumentNotFound)
956
+ end
957
+
958
+ should "not raise error for find with parent" do
959
+ john = DocSon.create(:name => 'John')
960
+
961
+ DocParent.find!(john._id).should == john
962
+ end
963
+
964
+ should "count scoped to class" do
965
+ john = DocSon.create(:name => 'John')
966
+ steve = DocSon.create(:name => 'Steve')
967
+ steph = DocDaughter.create(:name => 'Steph')
968
+ carrie = DocDaughter.create(:name => 'Carrie')
969
+
970
+ DocGrandSon.count.should == 0
971
+ DocSon.count.should == 2
972
+ DocDaughter.count.should == 2
973
+ DocParent.count.should == 4
974
+ end
975
+
976
+ should "know if it is single_collection_inherited?" do
977
+ DocParent.single_collection_inherited?.should be_false
978
+
979
+ DocDaughter.single_collection_inherited?.should be_true
980
+ DocSon.single_collection_inherited?.should be_true
981
+ end
982
+
983
+ should "know if single_collection_inherited_superclass?" do
984
+ DocParent.single_collection_inherited_superclass?.should be_false
985
+
986
+ DocDaughter.single_collection_inherited_superclass?.should be_true
987
+ DocSon.single_collection_inherited_superclass?.should be_true
988
+ DocGrandSon.single_collection_inherited_superclass?.should be_true
989
+ end
990
+
991
+ should "not be able to destroy each other" do
992
+ john = DocSon.create(:name => 'John')
993
+ steph = DocDaughter.create(:name => 'Steph')
994
+
995
+ lambda {
996
+ DocSon.destroy(steph._id)
997
+ }.should raise_error(MongoMapper::DocumentNotFound)
998
+ end
999
+
1000
+ should "not be able to delete each other" do
1001
+ john = DocSon.create(:name => 'John')
1002
+ steph = DocDaughter.create(:name => 'Steph')
1003
+
1004
+ lambda {
1005
+ DocSon.delete(steph._id)
1006
+ }.should_not change { DocParent.count }
1007
+ end
1008
+
1009
+ should "be able to destroy using parent" do
1010
+ john = DocSon.create(:name => 'John')
1011
+ steph = DocDaughter.create(:name => 'Steph')
1012
+
1013
+ lambda {
1014
+ DocParent.destroy_all
1015
+ }.should change { DocParent.count }.by(-2)
1016
+ end
1017
+
1018
+ should "be able to delete using parent" do
1019
+ john = DocSon.create(:name => 'John')
1020
+ steph = DocDaughter.create(:name => 'Steph')
1021
+
1022
+ lambda {
1023
+ DocParent.delete_all
1024
+ }.should change { DocParent.count }.by(-2)
1025
+ end
1026
+
1027
+ should "be able to reload parent inherited class" do
1028
+ brian = DocParent.create(:name => 'Brian')
1029
+ brian.name = 'B-Dawg'
1030
+ brian.reload
1031
+ brian.name.should == 'Brian'
1032
+ end
1033
+ end
1034
+
1035
+ context "timestamping" do
1036
+ setup do
1037
+ @klass = Doc do
1038
+ set_collection_name 'users'
1039
+
1040
+ key :first_name, String
1041
+ key :last_name, String
1042
+ key :age, Integer
1043
+ key :date, Date
1044
+ end
1045
+ @klass.timestamps!
1046
+ end
1047
+
1048
+ should "set created_at and updated_at on create" do
1049
+ doc = @klass.new(:first_name => 'John', :age => 27)
1050
+ doc.created_at.should be(nil)
1051
+ doc.updated_at.should be(nil)
1052
+ doc.save
1053
+ doc.created_at.should_not be(nil)
1054
+ doc.updated_at.should_not be(nil)
1055
+ end
1056
+
1057
+ should "not overwrite created_at if it already exists" do
1058
+ original_created_at = 1.month.ago
1059
+ doc = @klass.new(:first_name => 'John', :age => 27, :created_at => original_created_at)
1060
+ doc.created_at.to_i.should == original_created_at.to_i
1061
+ doc.updated_at.should be_nil
1062
+ doc.save
1063
+ doc.created_at.to_i.should == original_created_at.to_i
1064
+ doc.updated_at.should_not be_nil
1065
+ end
1066
+
1067
+ should "set updated_at on field update but leave created_at alone" do
1068
+ doc = @klass.create(:first_name => 'John', :age => 27)
1069
+ old_created_at = doc.created_at
1070
+ old_updated_at = doc.updated_at
1071
+ doc.first_name = 'Johnny'
1072
+
1073
+ Timecop.freeze(Time.now + 5.seconds) do
1074
+ doc.save
1075
+ end
1076
+
1077
+ doc.created_at.should == old_created_at
1078
+ doc.updated_at.should_not == old_updated_at
1079
+ end
1080
+
1081
+ should "set updated_at on document update but leave created_at alone" do
1082
+ doc = @klass.create(:first_name => 'John', :age => 27)
1083
+ old_created_at = doc.created_at
1084
+ old_updated_at = doc.updated_at
1085
+
1086
+ Timecop.freeze(Time.now + 5.seconds) do
1087
+ @klass.update(doc._id, { :first_name => 'Johnny' })
1088
+ end
1089
+
1090
+ doc = doc.reload
1091
+ doc.created_at.should == old_created_at
1092
+ doc.updated_at.should_not == old_updated_at
1093
+ end
1094
+ end
1095
+
1096
+ context "userstamping" do
1097
+ setup do
1098
+ @document.userstamps!
1099
+ end
1100
+
1101
+ should "add creator_id key" do
1102
+ @document.keys.keys.should include('creator_id')
1103
+ end
1104
+
1105
+ should "add updater_id key" do
1106
+ @document.keys.keys.should include('updater_id')
1107
+ end
1108
+
1109
+ should "add belongs_to creator" do
1110
+ @document.associations.keys.should include('creator')
1111
+ end
1112
+
1113
+ should "add belongs_to updater" do
1114
+ @document.associations.keys.should include('updater')
1115
+ end
1116
+ end
1117
+
1118
+ context "#exists?" do
1119
+ setup do
1120
+ @doc = @document.create(:first_name => "James", :age => 27)
1121
+ end
1122
+
1123
+ should "be true when at least one document exists" do
1124
+ @document.exists?.should == true
1125
+ end
1126
+
1127
+ should "be false when no documents exist" do
1128
+ @doc.destroy
1129
+ @document.exists?.should == false
1130
+ end
1131
+
1132
+ should "be true when at least one document exists that matches the conditions" do
1133
+ @document.exists?(:first_name => "James").should == true
1134
+ end
1135
+
1136
+ should "be false when no documents exist with the provided conditions" do
1137
+ @document.exists?(:first_name => "Jean").should == false
1138
+ end
1139
+ end
1140
+
1141
+ context "#reload" do
1142
+ setup do
1143
+ @foo_class = Doc do
1144
+ key :name
1145
+ end
1146
+
1147
+ @bar_class = EDoc do
1148
+ key :name
1149
+ end
1150
+
1151
+ @document.many :foos, :class => @foo_class
1152
+ @document.many :bars, :class => @bar_class
1153
+
1154
+ @instance = @document.create({
1155
+ :age => 39,
1156
+ :foos => [@foo_class.new(:name => '1')],
1157
+ :bars => [@bar_class.new(:name => '1')],
1158
+ })
1159
+ end
1160
+
1161
+ should "reload keys from the database" do
1162
+ @instance.age = 37
1163
+ @instance.age.should == 37
1164
+ @instance.reload
1165
+ @instance.age.should == 39
1166
+ end
1167
+
1168
+ should "reset all associations" do
1169
+ @instance.foos.expects(:reset).at_least_once
1170
+ @instance.bars.expects(:reset).at_least_once
1171
+ @instance.reload
1172
+ end
1173
+
1174
+ should "reinstantiate embedded associations" do
1175
+ @instance.reload
1176
+ @instance.bars.first.name.should == '1'
1177
+ end
1178
+
1179
+ should "return self" do
1180
+ @instance.reload.object_id.should == @instance.object_id
1181
+ end
1182
+
1183
+ should "raise DocumentNotFound if not found" do
1184
+ @instance.destroy
1185
+ assert_raises(MongoMapper::DocumentNotFound) { @instance.reload }
1186
+ end
1187
+ end
1188
+
1189
+ context "database has keys not defined in model" do
1190
+ setup do
1191
+ @id = Mongo::ObjectID.new
1192
+ @document.collection.insert({
1193
+ :_id => @id,
1194
+ :first_name => 'John',
1195
+ :last_name => 'Nunemaker',
1196
+ :age => 27,
1197
+ :favorite_color => 'red',
1198
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
1199
+ })
1200
+ end
1201
+
1202
+ should "assign all keys from database" do
1203
+ doc = @document.find(@id)
1204
+ doc.first_name.should == 'John'
1205
+ doc.last_name.should == 'Nunemaker'
1206
+ doc.age.should == 27
1207
+ doc.favorite_color.should == 'red'
1208
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
1209
+ end
1210
+ end
1211
+
1212
+ context "Indexing" do
1213
+ setup do
1214
+ drop_indexes(@document)
1215
+ end
1216
+
1217
+ should "allow creating index for a key" do
1218
+ @document.ensure_index :first_name
1219
+ @document.should have_index('first_name_1')
1220
+ end
1221
+
1222
+ should "allow creating unique index for a key" do
1223
+ @document.ensure_index :first_name, :unique => true
1224
+ @document.should have_index('first_name_1')
1225
+ end
1226
+
1227
+ should "allow creating index on multiple keys" do
1228
+ @document.ensure_index [[:first_name, 1], [:last_name, -1]]
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
+ @document.should have_index('father_1')
1242
+ end
1243
+ end
1244
+ end