mongo_mapper 0.6.8 → 0.6.9

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 (44) hide show
  1. data/README.rdoc +2 -17
  2. data/Rakefile +1 -1
  3. data/VERSION +1 -1
  4. data/lib/mongo_mapper/associations/base.rb +19 -10
  5. data/lib/mongo_mapper/associations/in_array_proxy.rb +137 -0
  6. data/lib/mongo_mapper/associations/one_proxy.rb +61 -0
  7. data/lib/mongo_mapper/associations/proxy.rb +0 -2
  8. data/lib/mongo_mapper/associations.rb +5 -3
  9. data/lib/mongo_mapper/callbacks.rb +30 -78
  10. data/lib/mongo_mapper/dirty.rb +5 -24
  11. data/lib/mongo_mapper/document.rb +117 -144
  12. data/lib/mongo_mapper/embedded_document.rb +7 -11
  13. data/lib/mongo_mapper/finder_options.rb +42 -30
  14. data/lib/mongo_mapper/mongo_mapper.rb +125 -0
  15. data/lib/mongo_mapper/pagination.rb +12 -1
  16. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +1 -0
  17. data/lib/mongo_mapper/serialization.rb +2 -2
  18. data/lib/mongo_mapper/serializers/json_serializer.rb +2 -46
  19. data/lib/mongo_mapper/support.rb +5 -2
  20. data/lib/mongo_mapper/validations.rb +1 -3
  21. data/lib/mongo_mapper.rb +8 -2
  22. data/mongo_mapper.gemspec +14 -8
  23. data/specs.watchr +3 -5
  24. data/test/functional/associations/test_belongs_to_proxy.rb +43 -0
  25. data/test/functional/associations/test_in_array_proxy.rb +309 -0
  26. data/test/functional/associations/test_many_documents_proxy.rb +103 -53
  27. data/test/functional/associations/test_many_polymorphic_proxy.rb +4 -3
  28. data/test/functional/associations/test_one_proxy.rb +131 -0
  29. data/test/functional/test_binary.rb +15 -0
  30. data/test/functional/test_document.rb +581 -631
  31. data/test/functional/test_modifiers.rb +242 -0
  32. data/test/functional/test_validations.rb +0 -17
  33. data/test/models.rb +1 -1
  34. data/test/support/timing.rb +1 -1
  35. data/test/unit/associations/test_base.rb +54 -13
  36. data/test/unit/test_document.rb +32 -0
  37. data/test/unit/test_embedded_document.rb +0 -9
  38. data/test/unit/test_finder_options.rb +36 -7
  39. data/test/unit/test_pagination.rb +6 -0
  40. data/test/unit/test_rails_compatibility.rb +4 -1
  41. data/test/unit/test_support.rb +4 -0
  42. metadata +12 -6
  43. data/lib/mongo_mapper/observing.rb +0 -50
  44. data/test/unit/test_observing.rb +0 -101
@@ -14,759 +14,560 @@ class DocumentTest < Test::Unit::TestCase
14
14
  end
15
15
  @document.collection.remove
16
16
  end
17
-
18
- context "Saving a document with a custom id" do
19
- should "clear custom id flag when saved" do
20
- @document.key :_id, String
21
- doc = @document.new(:id => '1234')
22
- doc.using_custom_id?.should be_true
23
- doc.save.should be_true
24
- doc.using_custom_id?.should be_false
25
- end
26
- end
27
-
28
- context "Saving a document with a blank binary value" do
17
+
18
+ context "Using key with type Array" do
29
19
  setup do
30
- @document.key :file, Binary
20
+ @document.key :tags, Array
31
21
  end
32
22
 
33
- should "not fail" do
34
- doc = @document.new(:file => nil)
35
- lambda {
36
- doc.save
37
- }.should_not raise_error
23
+ should "give correct default" do
24
+ doc = @document.new
25
+ doc.tags.should == []
38
26
  end
39
- end
40
27
 
41
- context "Loading a document from the database with keys that are not defined" do
42
- setup do
43
- @id = Mongo::ObjectID.new
44
- @document.collection.insert({
45
- :_id => @id,
46
- :first_name => 'John',
47
- :last_name => 'Nunemaker',
48
- :age => 27,
49
- :favorite_color => 'red',
50
- :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
51
- })
28
+ should "work with assignment" do
29
+ doc = @document.new
30
+ doc.tags = %w(foo bar)
31
+ doc.tags.should == %w(foo bar)
52
32
  end
53
33
 
54
- should "assign all keys from database" do
55
- doc = @document.find(@id)
56
- doc.first_name.should == 'John'
57
- doc.last_name.should == 'Nunemaker'
58
- doc.age.should == 27
59
- doc.favorite_color.should == 'red'
60
- doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
34
+ should "work with assignment after saving" do
35
+ doc = @document.new
36
+ doc.tags = %w(foo bar)
37
+ doc.save
38
+ doc.tags.should == %w(foo bar)
39
+ doc.reload.tags.should == %w(foo bar)
61
40
  end
62
- end
63
-
64
- context "Document Class Methods" do
65
- context "Using key with type Array" do
66
- setup do
67
- @document.key :tags, Array
68
- end
69
-
70
- should "give correct default" do
71
- doc = @document.new
72
- doc.tags.should == []
73
- end
74
-
75
- should "work with assignment" do
76
- doc = @document.new
77
- doc.tags = %w(foo bar)
78
- doc.tags.should == %w(foo bar)
79
- end
80
-
81
- should "work with assignment after saving" do
82
- doc = @document.new
83
- doc.tags = %w(foo bar)
84
- doc.save
85
- doc.tags.should == %w(foo bar)
86
- doc.reload.tags.should == %w(foo bar)
87
- end
88
-
89
- should "work with assignment then <<" do
90
- doc = @document.new
91
- doc.tags = []
92
- doc.tags << "foo"
93
- doc.tags.should == ["foo"]
94
- end
95
41
 
96
- should "work with <<" do
97
- doc = @document.new
98
- doc.tags << "foo"
99
- doc.tags.should == ["foo"]
100
- end
101
-
102
- should "work with << then save" do
103
- doc = @document.new
104
- doc.tags << "foo"
105
- doc.tags << "bar"
106
- doc.save
107
- doc.tags.should == %w(foo bar)
108
- doc.reload.tags.should == %w(foo bar)
109
- end
42
+ should "work with assignment then <<" do
43
+ doc = @document.new
44
+ doc.tags = []
45
+ doc.tags << "foo"
46
+ doc.tags.should == ["foo"]
110
47
  end
111
48
 
112
- context "Using key with type Hash" do
113
- setup do
114
- @document.key :foo, Hash
115
- end
49
+ should "work with <<" do
50
+ doc = @document.new
51
+ doc.tags << "foo"
52
+ doc.tags.should == ["foo"]
53
+ end
116
54
 
117
- should "give correct default" do
118
- doc = @document.new
119
- doc.foo.should == {}
120
- end
55
+ should "work with << then save" do
56
+ doc = @document.new
57
+ doc.tags << "foo"
58
+ doc.tags << "bar"
59
+ doc.save
60
+ doc.tags.should == %w(foo bar)
61
+ doc.reload.tags.should == %w(foo bar)
62
+ end
63
+ end
121
64
 
122
- should "work with []=" do
123
- doc = @document.new
124
- doc.foo["quux"] = "bar"
125
- doc.foo["quux"].should == "bar"
126
- doc.foo.should == { "quux" => "bar" }
127
- end
65
+ context "Using key with type Hash" do
66
+ setup do
67
+ @document.key :foo, Hash
68
+ end
128
69
 
129
- should "work with indifferent access" do
130
- doc = @document.new
131
- doc.foo = {:baz => 'bar'}
132
- doc.foo[:baz].should == 'bar'
133
- doc.foo['baz'].should == 'bar'
134
- end
70
+ should "give correct default" do
71
+ doc = @document.new
72
+ doc.foo.should == {}
73
+ end
135
74
 
136
- should "work with indifferent access after save" do
137
- doc = @document.new
138
- doc.foo = {:baz => 'bar'}
139
- doc.save
75
+ should "work with []=" do
76
+ doc = @document.new
77
+ doc.foo["quux"] = "bar"
78
+ doc.foo["quux"].should == "bar"
79
+ doc.foo.should == { "quux" => "bar" }
80
+ end
140
81
 
141
- doc = doc.reload
142
- doc.foo[:baz].should == 'bar'
143
- doc.foo['baz'].should == 'bar'
144
- end
82
+ should "work with indifferent access" do
83
+ doc = @document.new
84
+ doc.foo = {:baz => 'bar'}
85
+ doc.foo[:baz].should == 'bar'
86
+ doc.foo['baz'].should == 'bar'
145
87
  end
146
88
 
147
- context "Using key with custom type with default" do
148
- setup do
149
- @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
150
- end
89
+ should "work with indifferent access after save" do
90
+ doc = @document.new
91
+ doc.foo = {:baz => 'bar'}
92
+ doc.save
151
93
 
152
- should "default to default" do
153
- doc = @document.new
154
- doc.window.should == WindowSize.new(600, 480)
94
+ doc = doc.reload
95
+ doc.foo[:baz].should == 'bar'
96
+ doc.foo['baz'].should == 'bar'
97
+ end
98
+ end
155
99
 
156
- end
100
+ context "Using key with custom type with default" do
101
+ setup do
102
+ @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
103
+ end
157
104
 
158
- should "save and load from mongo" do
159
- doc = @document.new
160
- doc.save
105
+ should "default to default" do
106
+ doc = @document.new
107
+ doc.window.should == WindowSize.new(600, 480)
161
108
 
162
- doc = doc.reload
163
- doc.window.should == WindowSize.new(600, 480)
164
- end
165
109
  end
166
110
 
167
- context "Creating a single document" do
168
- setup do
169
- @doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
170
- end
171
-
172
- should "create a document in correct collection" do
173
- @document.count.should == 1
174
- end
111
+ should "save and load from mongo" do
112
+ doc = @document.new
113
+ doc.save
175
114
 
176
- should "automatically set id" do
177
- @doc_instance.id.should be_instance_of(Mongo::ObjectID)
178
- @doc_instance._id.should be_instance_of(Mongo::ObjectID)
179
- end
115
+ doc = doc.reload
116
+ doc.window.should == WindowSize.new(600, 480)
117
+ end
118
+ end
180
119
 
181
- should "no longer be new?" do
182
- @doc_instance.new?.should be_false
183
- end
120
+ context "ClassMethods#create (single document)" do
121
+ setup do
122
+ @doc_instance = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
123
+ end
184
124
 
185
- should "return instance of document" do
186
- @doc_instance.should be_instance_of(@document)
187
- @doc_instance.first_name.should == 'John'
188
- @doc_instance.last_name.should == 'Nunemaker'
189
- @doc_instance.age.should == 27
190
- end
125
+ should "create a document in correct collection" do
126
+ @document.count.should == 1
191
127
  end
192
128
 
193
- context "Creating a document with no attributes provided" do
194
- setup do
195
- @document = Class.new do
196
- include MongoMapper::Document
197
- set_collection_name 'test'
198
- end
199
- @document.collection.remove
200
- end
129
+ should "automatically set id" do
130
+ @doc_instance.id.should be_instance_of(Mongo::ObjectID)
131
+ @doc_instance._id.should be_instance_of(Mongo::ObjectID)
132
+ end
201
133
 
202
- should "create the document" do
203
- lambda {
204
- @document.create
205
- }.should change { @document.count }.by(1)
206
- end
134
+ should "no longer be new?" do
135
+ @doc_instance.new?.should be_false
207
136
  end
208
137
 
209
- context "Creating multiple documents" do
210
- setup do
211
- @doc_instances = @document.create([
212
- {:first_name => 'John', :last_name => 'Nunemaker', :age => '27'},
213
- {:first_name => 'Steve', :last_name => 'Smith', :age => '28'},
214
- ])
138
+ should "return instance of document" do
139
+ @doc_instance.should be_instance_of(@document)
140
+ @doc_instance.first_name.should == 'John'
141
+ @doc_instance.last_name.should == 'Nunemaker'
142
+ @doc_instance.age.should == 27
143
+ end
144
+
145
+ should "not fail if no attributes provided" do
146
+ document = Class.new do
147
+ include MongoMapper::Document
148
+ set_collection_name 'test'
215
149
  end
150
+ document.collection.remove
151
+
152
+ lambda { document.create }.should change { document.count }.by(1)
153
+ end
154
+ end
216
155
 
217
- should "create multiple documents" do
218
- @document.count.should == 2
219
- end
156
+ context "ClassMethods#create (multiple documents)" do
157
+ setup do
158
+ @doc_instances = @document.create([
159
+ {:first_name => 'John', :last_name => 'Nunemaker', :age => '27'},
160
+ {:first_name => 'Steve', :last_name => 'Smith', :age => '28'},
161
+ ])
162
+ end
220
163
 
221
- should "return an array of doc instances" do
222
- @doc_instances.map do |doc_instance|
223
- doc_instance.should be_instance_of(@document)
224
- end
225
- end
164
+ should "create multiple documents" do
165
+ @document.count.should == 2
226
166
  end
227
167
 
228
- context "Updating a document" do
229
- setup do
230
- doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
231
- @doc_instance = @document.update(doc._id, {:age => 40})
168
+ should "return an array of doc instances" do
169
+ @doc_instances.map do |doc_instance|
170
+ doc_instance.should be_instance_of(@document)
232
171
  end
172
+ end
173
+ end
233
174
 
234
- should "update attributes provided" do
235
- @doc_instance.age.should == 40
236
- end
175
+ context "ClassMethods#update (single document)" do
176
+ setup do
177
+ doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
178
+ @doc_instance = @document.update(doc._id, {:age => 40})
179
+ end
237
180
 
238
- should "not update existing attributes that were not set to update" do
239
- @doc_instance.first_name.should == 'John'
240
- @doc_instance.last_name.should == 'Nunemaker'
241
- end
181
+ should "update attributes provided" do
182
+ @doc_instance.age.should == 40
183
+ end
242
184
 
243
- should "not create new document" do
244
- @document.count.should == 1
245
- end
185
+ should "not update existing attributes that were not set to update" do
186
+ @doc_instance.first_name.should == 'John'
187
+ @doc_instance.last_name.should == 'Nunemaker'
246
188
  end
247
189
 
248
- should "raise error when updating single doc if not provided id and attributes" do
190
+ should "not create new document" do
191
+ @document.count.should == 1
192
+ end
193
+
194
+ should "raise error if not provided id" do
249
195
  doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
250
196
  lambda { @document.update }.should raise_error(ArgumentError)
197
+ end
198
+
199
+ should "raise error if not provided attributes" do
200
+ doc = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
251
201
  lambda { @document.update(doc._id) }.should raise_error(ArgumentError)
252
202
  lambda { @document.update(doc._id, [1]) }.should raise_error(ArgumentError)
253
203
  end
204
+ end
254
205
 
255
- context "Updating multiple documents" do
256
- setup do
257
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
258
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
259
-
260
- @doc_instances = @document.update({
261
- @doc1._id => {:age => 30},
262
- @doc2._id => {:age => 30},
263
- })
264
- end
206
+ context "ClassMethods#update (multiple documents)" do
207
+ setup do
208
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
209
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
265
210
 
266
- should "not create any new documents" do
267
- @document.count.should == 2
268
- end
211
+ @doc_instances = @document.update({
212
+ @doc1._id => {:age => 30},
213
+ @doc2._id => {:age => 30},
214
+ })
215
+ end
269
216
 
270
- should "should return an array of doc instances" do
271
- @doc_instances.map do |doc_instance|
272
- doc_instance.should be_instance_of(@document)
273
- end
274
- end
217
+ should "not create any new documents" do
218
+ @document.count.should == 2
219
+ end
275
220
 
276
- should "update the documents" do
277
- @document.find(@doc1._id).age.should == 30
278
- @document.find(@doc2._id).age.should == 30
221
+ should "should return an array of doc instances" do
222
+ @doc_instances.map do |doc_instance|
223
+ doc_instance.should be_instance_of(@document)
279
224
  end
280
225
  end
281
226
 
282
- should "raise error when updating multiple documents if not a hash" do
227
+ should "update the documents" do
228
+ @document.find(@doc1._id).age.should == 30
229
+ @document.find(@doc2._id).age.should == 30
230
+ end
231
+
232
+ should "raise error if not a hash" do
283
233
  lambda { @document.update([1, 2]) }.should raise_error(ArgumentError)
284
234
  end
235
+ end
285
236
 
286
- context "Finding documents" do
287
- setup do
288
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
289
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
290
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
291
- end
292
-
293
- should "return nil if nothing provided for find" do
294
- @document.find.should be_nil
295
- end
296
-
297
- should "raise document not found if nothing provided for find!" do
298
- lambda { @document.find! }.should raise_error(MongoMapper::DocumentNotFound)
299
- end
237
+ context "ClassMethods#find" do
238
+ setup do
239
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
240
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
241
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
242
+ end
300
243
 
301
- context "with a single id" do
302
- should "work" do
303
- @document.find(@doc1._id).should == @doc1
304
- end
244
+ should "return nil if nothing provided for find" do
245
+ @document.find.should be_nil
246
+ end
305
247
 
306
- should "return nil if document not found with find" do
307
- @document.find(123).should be_nil
308
- end
248
+ should "raise document not found if nothing provided for find!" do
249
+ lambda { @document.find! }.should raise_error(MongoMapper::DocumentNotFound)
250
+ end
309
251
 
310
- should "raise error if document not found with find!" do
311
- lambda {
312
- @document.find!(123)
313
- }.should raise_error(MongoMapper::DocumentNotFound)
314
- end
252
+ context "(with a single id)" do
253
+ should "work" do
254
+ @document.find(@doc1._id).should == @doc1
315
255
  end
316
256
 
317
- context "with multiple id's" do
318
- should "work as arguments" do
319
- @document.find(@doc1._id, @doc2._id).should == [@doc1, @doc2]
320
- end
321
-
322
- should "work as array" do
323
- @document.find([@doc1._id, @doc2._id]).should == [@doc1, @doc2]
324
- end
325
-
326
- should "return array if array only has one element" do
327
- @document.find([@doc1._id]).should == [@doc1]
328
- end
257
+ should "return nil if document not found with find" do
258
+ @document.find(123).should be_nil
329
259
  end
330
260
 
331
- should "be able to find using condition auto-detection" do
332
- @document.first(:first_name => 'John').should == @doc1
333
- @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
261
+ should "raise error if document not found with find!" do
262
+ lambda {
263
+ @document.find!(123)
264
+ }.should raise_error(MongoMapper::DocumentNotFound)
334
265
  end
266
+ end
335
267
 
336
- context "with :all" do
337
- should "find all documents" do
338
- @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
339
- end
340
-
341
- should "be able to add conditions" do
342
- @document.find(:all, :first_name => 'John').should == [@doc1]
343
- end
268
+ context "(with multiple id's)" do
269
+ should "work as arguments" do
270
+ @document.find(@doc1._id, @doc2._id).should == [@doc1, @doc2]
344
271
  end
345
272
 
346
- context "with #all" do
347
- should "find all documents based on criteria" do
348
- @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
349
- @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
350
- end
273
+ should "work as array" do
274
+ @document.find([@doc1._id, @doc2._id]).should == [@doc1, @doc2]
351
275
  end
352
276
 
353
- context "with :first" do
354
- should "find first document" do
355
- @document.find(:first, :order => 'first_name').should == @doc1
356
- end
277
+ should "return array if array only has one element" do
278
+ @document.find([@doc1._id]).should == [@doc1]
357
279
  end
280
+ end
358
281
 
359
- context "with #first" do
360
- should "find first document based on criteria" do
361
- @document.first(:order => 'first_name').should == @doc1
362
- @document.first(:age => 28).should == @doc2
363
- end
364
- end
282
+ should "be able to find using condition auto-detection" do
283
+ @document.first(:first_name => 'John').should == @doc1
284
+ @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
285
+ end
365
286
 
366
- context "with :last" do
367
- should "find last document" do
368
- @document.find(:last, :order => 'age').should == @doc2
369
- end
287
+ context "(with :all)" do
288
+ should "find all documents" do
289
+ @document.find(:all, :order => 'first_name').should == [@doc1, @doc3, @doc2]
370
290
  end
371
291
 
372
- context "with #last" do
373
- should "find last document based on criteria" do
374
- @document.last(:order => 'age').should == @doc2
375
- @document.last(:order => 'age', :age => 28).should == @doc2
376
- end
377
-
378
- should "raise error if no order provided" do
379
- lambda { @document.last() }.should raise_error
380
- end
292
+ should "be able to add conditions" do
293
+ @document.find(:all, :first_name => 'John').should == [@doc1]
381
294
  end
295
+ end
382
296
 
383
- context "with :find_by" do
384
- should "find document based on argument" do
385
- @document.find_by_first_name('John').should == @doc1
386
- @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
387
- @document.find_by_age(27).should == @doc1
388
- end
389
-
390
- should "not raise error" do
391
- @document.find_by_first_name('Mongo').should be_nil
392
- end
297
+ context "(with #all)" do
298
+ should "find all documents based on criteria" do
299
+ @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
300
+ @document.all(:last_name => 'Nunemaker', :order => 'age desc').should == [@doc1, @doc3]
301
+ end
302
+ end
393
303
 
394
- should "define a method for each key" do
395
- @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
396
- end
304
+ context "(with :first)" do
305
+ should "find first document" do
306
+ @document.find(:first, :order => 'first_name').should == @doc1
397
307
  end
308
+ end
398
309
 
399
- context "with dynamic finders" do
400
- should "find document based on all arguments" do
401
- @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
402
- end
403
-
404
- should "not find the document if an argument is wrong" do
405
- @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
406
- end
407
-
408
- should "find all documents based on arguments" do
409
- docs = @document.find_all_by_last_name('Nunemaker')
410
- docs.should be_kind_of(Array)
411
- docs.should include(@doc1)
412
- docs.should include(@doc3)
413
- end
414
-
415
- should "initialize document with given arguments" do
416
- doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
417
- doc.should be_new
418
- doc.first_name.should == 'David'
419
- end
420
-
421
- should "not initialize document if document is found" do
422
- doc = @document.find_or_initialize_by_first_name('John')
423
- doc.should_not be_new
424
- end
425
-
426
- should "create document with given arguments" do
427
- doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
428
- doc.should_not be_new
429
- doc.first_name.should == 'David'
430
- end
431
-
432
- should "raise error if document is not found when using !" do
433
- lambda {
434
- @document.find_by_first_name_and_last_name!(1,2)
435
- }.should raise_error(MongoMapper::DocumentNotFound)
436
- end
310
+ context "(with #first)" do
311
+ should "find first document based on criteria" do
312
+ @document.first(:order => 'first_name').should == @doc1
313
+ @document.first(:age => 28).should == @doc2
437
314
  end
438
- end # finding documents
315
+ end
439
316
 
440
- context "Finding document by id" do
441
- setup do
442
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
443
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
317
+ context "(with :last)" do
318
+ should "find last document" do
319
+ @document.find(:last, :order => 'age').should == @doc2
444
320
  end
321
+ end
445
322
 
446
- should "be able to find by id" do
447
- @document.find_by_id(@doc1._id).should == @doc1
448
- @document.find_by_id(@doc2._id).should == @doc2
323
+ context "(with #last)" do
324
+ should "find last document based on criteria" do
325
+ @document.last(:order => 'age').should == @doc2
326
+ @document.last(:order => 'age', :age => 28).should == @doc2
449
327
  end
450
328
 
451
- should "return nil if document not found" do
452
- @document.find_by_id(1234).should be(nil)
329
+ should "raise error if no order provided" do
330
+ lambda { @document.last() }.should raise_error
453
331
  end
454
332
  end
455
333
 
456
- context "Deleting a document" do
457
- setup do
458
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
459
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
460
- @document.delete(@doc1._id)
334
+ context "(with :find_by)" do
335
+ should "find document based on argument" do
336
+ @document.find_by_first_name('John').should == @doc1
337
+ @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
338
+ @document.find_by_age(27).should == @doc1
461
339
  end
462
340
 
463
- should "remove document from collection" do
464
- @document.count.should == 1
341
+ should "not raise error" do
342
+ @document.find_by_first_name('Mongo').should be_nil
465
343
  end
466
344
 
467
- should "not remove other documents" do
468
- @document.find(@doc2._id).should_not be(nil)
345
+ should "define a method for each key" do
346
+ @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
469
347
  end
470
348
  end
471
349
 
472
- context "Deleting multiple documents" do
473
- should "work with multiple arguments" 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
350
+ context "(with dynamic finders)" do
351
+ should "find document based on all arguments" do
352
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
480
353
  end
481
354
 
482
- should "work with array as argument" do
483
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
484
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
485
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
486
- @document.delete([@doc1._id, @doc2._id])
355
+ should "not find the document if an argument is wrong" do
356
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
357
+ end
487
358
 
488
- @document.count.should == 1
359
+ should "find all documents based on arguments" do
360
+ docs = @document.find_all_by_last_name('Nunemaker')
361
+ docs.should be_kind_of(Array)
362
+ docs.should include(@doc1)
363
+ docs.should include(@doc3)
489
364
  end
490
- end
491
365
 
492
- context "Deleting all documents" do
493
- setup do
494
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
495
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
496
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
366
+ should "initialize document with given arguments" do
367
+ doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
368
+ doc.should be_new
369
+ doc.first_name.should == 'David'
497
370
  end
498
371
 
499
- should "remove all documents when given no conditions" do
500
- @document.delete_all
501
- @document.count.should == 0
372
+ should "not initialize document if document is found" do
373
+ doc = @document.find_or_initialize_by_first_name('John')
374
+ doc.should_not be_new
502
375
  end
503
376
 
504
- should "only remove matching documents when given conditions" do
505
- @document.delete_all({:first_name => 'John'})
506
- @document.count.should == 2
377
+ should "create document with given arguments" do
378
+ doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
379
+ doc.should_not be_new
380
+ doc.first_name.should == 'David'
507
381
  end
508
382
 
509
- should "convert the conditions to mongo criteria" do
510
- @document.delete_all(:age => [26, 27])
511
- @document.count.should == 1
383
+ should "raise error if document is not found when using !" do
384
+ lambda {
385
+ @document.find_by_first_name_and_last_name!(1,2)
386
+ }.should raise_error(MongoMapper::DocumentNotFound)
512
387
  end
513
388
  end
389
+ end # finding documents
514
390
 
515
- context "Destroying a document" do
516
- setup do
517
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
518
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
519
- @document.destroy(@doc1._id)
520
- end
391
+ context "ClassMethods#find_by_id" do
392
+ setup do
393
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
394
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
395
+ end
521
396
 
522
- should "remove document from collection" do
523
- @document.count.should == 1
524
- end
397
+ should "be able to find by id" do
398
+ @document.find_by_id(@doc1._id).should == @doc1
399
+ @document.find_by_id(@doc2._id).should == @doc2
400
+ end
525
401
 
526
- should "not remove other documents" do
527
- @document.find(@doc2._id).should_not be(nil)
528
- end
402
+ should "return nil if document not found" do
403
+ @document.find_by_id(1234).should be(nil)
529
404
  end
405
+ end
530
406
 
531
- context "Destroying multiple documents" do
532
- should "work with multiple arguments" 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
407
+ context "ClassMethods#delete (single document)" do
408
+ setup do
409
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
410
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
411
+ @document.delete(@doc1._id)
412
+ end
540
413
 
541
- should "work with array as argument" do
542
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
543
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
544
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
545
- @document.destroy([@doc1._id, @doc2._id])
414
+ should "remove document from collection" do
415
+ @document.count.should == 1
416
+ end
546
417
 
547
- @document.count.should == 1
548
- end
418
+ should "not remove other documents" do
419
+ @document.find(@doc2._id).should_not be(nil)
549
420
  end
421
+ end
550
422
 
551
- context "Destroying all documents" do
552
- setup do
553
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
554
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
555
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
556
- end
423
+ context "ClassMethods#delete (multiple documents)" do
424
+ should "work with multiple arguments" do
425
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
426
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
427
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
428
+ @document.delete(@doc1._id, @doc2._id)
557
429
 
558
- should "remove all documents when given no conditions" do
559
- @document.destroy_all
560
- @document.count.should == 0
561
- end
430
+ @document.count.should == 1
431
+ end
562
432
 
563
- should "only remove matching documents when given conditions" do
564
- @document.destroy_all(:first_name => 'John')
565
- @document.count.should == 2
566
- @document.destroy_all(:age => 26)
567
- @document.count.should == 1
568
- end
433
+ should "work with array as argument" do
434
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
435
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
436
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
437
+ @document.delete([@doc1._id, @doc2._id])
569
438
 
570
- should "convert the conditions to mongo criteria" do
571
- @document.destroy_all(:age => [26, 27])
572
- @document.count.should == 1
573
- end
439
+ @document.count.should == 1
574
440
  end
441
+ end
575
442
 
576
- context ":dependent" do
577
- setup do
578
- # FIXME: make use of already defined models
579
- class ::Property
580
- include MongoMapper::Document
581
- end
582
- Property.collection.remove
443
+ context "ClassMethods#delete_all" do
444
+ setup do
445
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
446
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
447
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
448
+ end
583
449
 
584
- class ::Thing
585
- include MongoMapper::Document
586
- key :name, String
587
- end
588
- Thing.collection.remove
589
- end
450
+ should "remove all documents when given no conditions" do
451
+ @document.delete_all
452
+ @document.count.should == 0
453
+ end
590
454
 
591
- teardown do
592
- Object.send :remove_const, 'Property' if defined?(::Property)
593
- Object.send :remove_const, 'Thing' if defined?(::Thing)
594
- end
455
+ should "only remove matching documents when given conditions" do
456
+ @document.delete_all({:first_name => 'John'})
457
+ @document.count.should == 2
458
+ end
595
459
 
596
- context "many" do
597
- context "=> destroy" do
598
- setup do
599
- Property.key :thing_id, ObjectId
600
- Property.belongs_to :thing, :dependent => :destroy
601
- Thing.many :properties, :dependent => :destroy
602
-
603
- @thing = Thing.create(:name => "Tree")
604
- @property1 = Property.create
605
- @property2 = Property.create
606
- @property3 = Property.create
607
- @thing.properties << @property1
608
- @thing.properties << @property2
609
- @thing.properties << @property3
610
- end
611
-
612
- should "should destroy the associated documents" do
613
- @thing.properties.count.should == 3
614
- @thing.destroy
615
- @thing.properties.count.should == 0
616
- Property.count.should == 0
617
- end
618
- end
619
-
620
- context "=> delete_all" do
621
- setup do
622
- Property.key :thing_id, ObjectId
623
- Property.belongs_to :thing
624
- Thing.has_many :properties, :dependent => :delete_all
625
-
626
- @thing = Thing.create(:name => "Tree")
627
- @property1 = Property.create
628
- @property2 = Property.create
629
- @property3 = Property.create
630
- @thing.properties << @property1
631
- @thing.properties << @property2
632
- @thing.properties << @property3
633
- end
634
-
635
- should "should delete associated documents" do
636
- @thing.properties.count.should == 3
637
- @thing.destroy
638
- @thing.properties.count.should == 0
639
- Property.count.should == 0
640
- end
641
- end
642
-
643
- context "=> nullify" do
644
- setup do
645
- Property.key :thing_id, ObjectId
646
- Property.belongs_to :thing
647
- Thing.has_many :properties, :dependent => :nullify
648
-
649
- @thing = Thing.create(:name => "Tree")
650
- @property1 = Property.create
651
- @property2 = Property.create
652
- @property3 = Property.create
653
- @thing.properties << @property1
654
- @thing.properties << @property2
655
- @thing.properties << @property3
656
- end
657
-
658
- should "should nullify relationship but not destroy associated documents" do
659
- @thing.properties.count.should == 3
660
- @thing.destroy
661
- @thing.properties.count.should == 0
662
- Property.count.should == 3
663
- end
664
- end
665
- end
460
+ should "convert the conditions to mongo criteria" do
461
+ @document.delete_all(:age => [26, 27])
462
+ @document.count.should == 1
463
+ end
464
+ end
666
465
 
667
- context "belongs_to" do
668
- context "=> destroy" do
669
- setup do
670
- Property.key :thing_id, ObjectId
671
- Property.belongs_to :thing, :dependent => :destroy
672
- Thing.has_many :properties
673
-
674
- @thing = Thing.create(:name => "Tree")
675
- @property1 = Property.create
676
- @property2 = Property.create
677
- @property3 = Property.create
678
- @thing.properties << @property1
679
- @thing.properties << @property2
680
- @thing.properties << @property3
681
- end
682
-
683
- should "not execute on a belongs_to association" do
684
- Thing.count.should == 1
685
- @property1.destroy
686
- Thing.count.should == 1
687
- @property1.should be_frozen
688
- end
689
- end
690
- end
466
+ context "ClassMethods#destroy (single document)" do
467
+ setup do
468
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
469
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
470
+ @document.destroy(@doc1._id)
691
471
  end
692
472
 
693
- context "Counting documents in collection" do
694
- setup do
695
- @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
696
- @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
697
- @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
698
- end
473
+ should "remove document from collection" do
474
+ @document.count.should == 1
475
+ end
699
476
 
700
- should "count all with no arguments" do
701
- @document.count.should == 3
702
- end
477
+ should "not remove other documents" do
478
+ @document.find(@doc2._id).should_not be(nil)
479
+ end
480
+ end
703
481
 
704
- should "return 0 if there are no documents in the collection" do
705
- @document.delete_all
706
- @document.count.should == 0
707
- end
482
+ context "ClassMethods#destroy (multiple documents)" do
483
+ should "work with multiple arguments" do
484
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
485
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
486
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
487
+ @document.destroy(@doc1._id, @doc2._id)
488
+
489
+ @document.count.should == 1
490
+ end
708
491
 
709
- should "return 0 if the collection does not exist" do
710
- klass = Class.new do
711
- include MongoMapper::Document
712
- set_collection_name 'foobarbazwickdoesnotexist'
713
- end
714
- @document.collection.remove
492
+ should "work with array as argument" do
493
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
494
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
495
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
496
+ @document.destroy([@doc1._id, @doc2._id])
715
497
 
716
- klass.count.should == 0
717
- end
498
+ @document.count.should == 1
499
+ end
500
+ end
718
501
 
719
- should "return count for matching documents if conditions provided" do
720
- @document.count(:age => 27).should == 1
721
- end
502
+ context "ClassMethods#destroy_all" do
503
+ setup do
504
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
505
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
506
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
507
+ end
722
508
 
723
- should "convert the conditions to mongo criteria" do
724
- @document.count(:age => [26, 27]).should == 2
725
- end
509
+ should "remove all documents when given no conditions" do
510
+ @document.destroy_all
511
+ @document.count.should == 0
726
512
  end
727
513
 
728
- context "Indexing" do
729
- setup do
730
- @document.collection.drop_indexes
731
- end
514
+ should "only remove matching documents when given conditions" do
515
+ @document.destroy_all(:first_name => 'John')
516
+ @document.count.should == 2
517
+ @document.destroy_all(:age => 26)
518
+ @document.count.should == 1
519
+ end
732
520
 
733
- should "allow creating index for a key" do
734
- @document.ensure_index :first_name
735
- MongoMapper.ensure_indexes!
521
+ should "convert the conditions to mongo criteria" do
522
+ @document.destroy_all(:age => [26, 27])
523
+ @document.count.should == 1
524
+ end
525
+ end
736
526
 
737
- @document.should have_index('first_name_1')
738
- end
527
+ context "ClassMethods#count" do
528
+ setup do
529
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
530
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
531
+ @doc3 = @document.create({:first_name => 'Steph', :last_name => 'Nunemaker', :age => '26'})
532
+ end
739
533
 
740
- should "allow creating unique index for a key" do
741
- @document.ensure_index :first_name, :unique => true
742
- MongoMapper.ensure_indexes!
534
+ should "count all with no arguments" do
535
+ @document.count.should == 3
536
+ end
743
537
 
744
- @document.should have_index('first_name_1')
745
- end
538
+ should "return 0 if there are no documents in the collection" do
539
+ @document.delete_all
540
+ @document.count.should == 0
541
+ end
746
542
 
747
- should "allow creating index on multiple keys" do
748
- @document.ensure_index [[:first_name, 1], [:last_name, -1]]
749
- MongoMapper.ensure_indexes!
750
-
751
- # order is different for different versions of ruby so instead of
752
- # just checking have_index('first_name_1_last_name_-1') I'm checking
753
- # the values of the indexes to make sure the index creation was successful
754
- @document.collection.index_information.detect do |index|
755
- keys = index[1]
756
- keys.include?(['first_name', 1]) && keys.include?(['last_name', -1])
757
- end.should_not be_nil
543
+ should "return 0 if the collection does not exist" do
544
+ klass = Class.new do
545
+ include MongoMapper::Document
546
+ set_collection_name 'foobarbazwickdoesnotexist'
758
547
  end
548
+ @document.collection.remove
759
549
 
760
- should "work with :index shortcut when defining key" do
761
- @document.key :father, String, :index => true
762
- MongoMapper.ensure_indexes!
550
+ klass.count.should == 0
551
+ end
763
552
 
764
- @document.should have_index('father_1')
765
- end
553
+ should "return count for matching documents if conditions provided" do
554
+ @document.count(:age => 27).should == 1
555
+ end
556
+
557
+ should "convert the conditions to mongo criteria" do
558
+ @document.count(:age => [26, 27]).should == 2
766
559
  end
767
- end # Document Class Methods
560
+ end
561
+
562
+ should "have instance method for collection" do
563
+ @document.new.collection.name.should == @document.collection.name
564
+ end
565
+
566
+ should "have instance method for database" do
567
+ @document.new.database.should == @document.database
568
+ end
768
569
 
769
- context "Saving a new document" do
570
+ context "#save (new document)" do
770
571
  setup do
771
572
  @doc = @document.new(:first_name => 'John', :age => '27')
772
573
  @doc.save
@@ -815,7 +616,7 @@ class DocumentTest < Test::Unit::TestCase
815
616
  end
816
617
  end
817
618
 
818
- context "Saving an existing document" do
619
+ context "#save (existing document)" do
819
620
  setup do
820
621
  @doc = @document.create(:first_name => 'John', :age => '27')
821
622
  @doc.first_name = 'Johnny'
@@ -846,7 +647,7 @@ class DocumentTest < Test::Unit::TestCase
846
647
  end
847
648
  end
848
649
 
849
- context "Calling update attributes on a new document" do
650
+ context "#update_attributes (new document)" do
850
651
  setup do
851
652
  @doc = @document.new(:first_name => 'John', :age => '27')
852
653
  @doc.update_attributes(:first_name => 'Johnny', :age => 30)
@@ -878,7 +679,7 @@ class DocumentTest < Test::Unit::TestCase
878
679
  end
879
680
  end
880
681
 
881
- context "Updating an existing document using update attributes" do
682
+ context "#update_attributes (existing document)" do
882
683
  setup do
883
684
  @doc = @document.create(:first_name => 'John', :age => '27')
884
685
  @doc.update_attributes(:first_name => 'Johnny', :age => 30)
@@ -900,7 +701,7 @@ class DocumentTest < Test::Unit::TestCase
900
701
  end
901
702
  end
902
703
 
903
- context "update_attributes" do
704
+ context "#update_attributes" do
904
705
  setup do
905
706
  @document.key :foo, String, :required => true
906
707
  end
@@ -913,8 +714,56 @@ class DocumentTest < Test::Unit::TestCase
913
714
  @document.new.update_attributes({}).should be_false
914
715
  end
915
716
  end
717
+
718
+ context "#save (with validations off)" do
719
+ setup do
720
+ @document = Class.new do
721
+ include MongoMapper::Document
722
+ set_collection_name 'test'
723
+ key :name, String, :required => true
724
+ end
725
+ @document.collection.remove
726
+ end
916
727
 
917
- context "Destroying a document that exists" do
728
+ should "insert document" do
729
+ doc = @document.new
730
+ doc.save(:validate => false)
731
+ @document.count.should == 1
732
+ end
733
+
734
+ should "work with false passed to save" do
735
+ doc = @document.new
736
+ doc.save(false)
737
+ @document.count.should == 1
738
+ end
739
+ end
740
+
741
+ context "#save (with options)" do
742
+ setup do
743
+ MongoMapper.ensured_indexes = []
744
+
745
+ @document = Class.new do
746
+ include MongoMapper::Document
747
+ set_collection_name 'test'
748
+ key :name, String
749
+ ensure_index :name, :unique => true
750
+ end
751
+ @document.collection.drop_indexes
752
+
753
+ MongoMapper.ensure_indexes!
754
+ end
755
+
756
+ should "allow passing safe" do
757
+ doc = @document.new(:name => 'John')
758
+ doc.save
759
+
760
+ assert_raises(Mongo::OperationFailure) do
761
+ @document.new(:name => 'John').save(:safe => true)
762
+ end
763
+ end
764
+ end
765
+
766
+ context "#destroy" do
918
767
  setup do
919
768
  @doc = @document.create(:first_name => 'John', :age => '27')
920
769
  @doc.destroy
@@ -923,30 +772,35 @@ class DocumentTest < Test::Unit::TestCase
923
772
  should "remove the document from the collection" do
924
773
  @document.count.should == 0
925
774
  end
926
-
927
- should "raise error if assignment is attempted" do
928
- lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
929
- end
930
-
931
- should "do nothing if destroy is called again" do
932
- @doc.destroy.should be_false
933
- end
934
775
  end
935
-
936
- context "Destroying a document that is a new" do
776
+
777
+ context "#delete" do
937
778
  setup do
938
- setup do
939
- @doc = @document.new(:first_name => 'John Nunemaker', :age => '27')
940
- @doc.destroy
941
- end
942
-
943
- should "not affect collection count" do
944
- @document.collection.count.should == 0
779
+ @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
780
+ @doc2 = @document.create({:first_name => 'Steve', :last_name => 'Smith', :age => '28'})
781
+
782
+ @document.class_eval do
783
+ before_destroy :before_destroy_callback
784
+ after_destroy :after_destroy_callback
785
+
786
+ def history; @history ||= [] end
787
+ def before_destroy_callback; history << :after_destroy end
788
+ def after_destroy_callback; history << :after_destroy end
945
789
  end
790
+
791
+ @doc1.delete
792
+ end
946
793
 
947
- should "raise error if assignment is attempted" do
948
- lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
949
- end
794
+ should "remove document from collection" do
795
+ @document.count.should == 1
796
+ end
797
+
798
+ should "not remove other documents" do
799
+ @document.find(@doc2.id).should_not be(nil)
800
+ end
801
+
802
+ should "not call before/after destroy callbacks" do
803
+ @doc1.history.should == []
950
804
  end
951
805
  end
952
806
 
@@ -1164,6 +1018,28 @@ class DocumentTest < Test::Unit::TestCase
1164
1018
  end
1165
1019
  end
1166
1020
 
1021
+ context "userstamping" do
1022
+ setup do
1023
+ @document.userstamps!
1024
+ end
1025
+
1026
+ should "add creator_id key" do
1027
+ @document.keys.keys.should include('creator_id')
1028
+ end
1029
+
1030
+ should "add updater_id key" do
1031
+ @document.keys.keys.should include('updater_id')
1032
+ end
1033
+
1034
+ should "add belongs_to creator" do
1035
+ @document.associations.keys.should include('creator')
1036
+ end
1037
+
1038
+ should "add belongs_to updater" do
1039
+ @document.associations.keys.should include('updater')
1040
+ end
1041
+ end
1042
+
1167
1043
  context "#exist?" do
1168
1044
  setup do
1169
1045
  @doc = @document.create(:first_name => "James", :age => 27)
@@ -1187,7 +1063,7 @@ class DocumentTest < Test::Unit::TestCase
1187
1063
  end
1188
1064
  end
1189
1065
 
1190
- context "reload" do
1066
+ context "#reload" do
1191
1067
  setup do
1192
1068
  @foo_class = Class.new do
1193
1069
  include MongoMapper::Document
@@ -1232,4 +1108,78 @@ class DocumentTest < Test::Unit::TestCase
1232
1108
  @instance.reload.object_id.should == @instance.object_id
1233
1109
  end
1234
1110
  end
1111
+
1112
+ context "Saving a document with a custom id" do
1113
+ should "clear custom id flag when saved" do
1114
+ @document.key :_id, String
1115
+ doc = @document.new(:id => '1234')
1116
+ doc.using_custom_id?.should be_true
1117
+ doc.save.should be_true
1118
+ doc.using_custom_id?.should be_false
1119
+ end
1120
+ end
1121
+
1122
+ context "Loading a document from the database with keys that are not defined" do
1123
+ setup do
1124
+ @id = Mongo::ObjectID.new
1125
+ @document.collection.insert({
1126
+ :_id => @id,
1127
+ :first_name => 'John',
1128
+ :last_name => 'Nunemaker',
1129
+ :age => 27,
1130
+ :favorite_color => 'red',
1131
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
1132
+ })
1133
+ end
1134
+
1135
+ should "assign all keys from database" do
1136
+ doc = @document.find(@id)
1137
+ doc.first_name.should == 'John'
1138
+ doc.last_name.should == 'Nunemaker'
1139
+ doc.age.should == 27
1140
+ doc.favorite_color.should == 'red'
1141
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
1142
+ end
1143
+ end
1144
+
1145
+ context "Indexing" do
1146
+ setup do
1147
+ MongoMapper.ensured_indexes = []
1148
+ @document.collection.drop_indexes
1149
+ end
1150
+
1151
+ should "allow creating index for a key" do
1152
+ @document.ensure_index :first_name
1153
+ MongoMapper.ensure_indexes!
1154
+
1155
+ @document.should have_index('first_name_1')
1156
+ end
1157
+
1158
+ should "allow creating unique index for a key" do
1159
+ @document.ensure_index :first_name, :unique => true
1160
+ MongoMapper.ensure_indexes!
1161
+
1162
+ @document.should have_index('first_name_1')
1163
+ end
1164
+
1165
+ should "allow creating index on multiple keys" do
1166
+ @document.ensure_index [[:first_name, 1], [:last_name, -1]]
1167
+ MongoMapper.ensure_indexes!
1168
+
1169
+ # order is different for different versions of ruby so instead of
1170
+ # just checking have_index('first_name_1_last_name_-1') I'm checking
1171
+ # the values of the indexes to make sure the index creation was successful
1172
+ @document.collection.index_information.detect do |index|
1173
+ keys = index[1]
1174
+ keys.include?(['first_name', 1]) && keys.include?(['last_name', -1])
1175
+ end.should_not be_nil
1176
+ end
1177
+
1178
+ should "work with :index shortcut when defining key" do
1179
+ @document.key :father, String, :index => true
1180
+ MongoMapper.ensure_indexes!
1181
+
1182
+ @document.should have_index('father_1')
1183
+ end
1184
+ end
1235
1185
  end