mongo_mapper 0.9.2 → 0.10.0

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 (40) hide show
  1. data/UPGRADES +6 -0
  2. data/lib/mongo_mapper.rb +1 -2
  3. data/lib/mongo_mapper/document.rb +0 -1
  4. data/lib/mongo_mapper/embedded_document.rb +0 -1
  5. data/lib/mongo_mapper/extensions/float.rb +1 -1
  6. data/lib/mongo_mapper/plugins.rb +2 -8
  7. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +2 -0
  8. data/lib/mongo_mapper/plugins/associations/many_association.rb +4 -4
  9. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +9 -1
  10. data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
  11. data/lib/mongo_mapper/plugins/associations/one_association.rb +29 -1
  12. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +0 -1
  13. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +43 -16
  14. data/lib/mongo_mapper/plugins/clone.rb +1 -1
  15. data/lib/mongo_mapper/plugins/dirty.rb +6 -15
  16. data/lib/mongo_mapper/plugins/document.rb +5 -5
  17. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +3 -3
  18. data/lib/mongo_mapper/plugins/keys.rb +0 -19
  19. data/lib/mongo_mapper/plugins/keys/key.rb +0 -4
  20. data/lib/mongo_mapper/railtie.rb +1 -2
  21. data/lib/mongo_mapper/version.rb +1 -1
  22. data/test/functional/associations/test_belongs_to_proxy.rb +15 -0
  23. data/test/functional/associations/test_many_documents_proxy.rb +161 -0
  24. data/test/functional/associations/test_one_as_proxy.rb +485 -0
  25. data/test/functional/associations/test_one_proxy.rb +188 -27
  26. data/test/functional/test_dirty.rb +9 -0
  27. data/test/functional/test_document.rb +5 -0
  28. data/test/support/railtie.rb +4 -0
  29. data/test/support/railtie/autoloaded.rb +2 -0
  30. data/test/support/railtie/not_autoloaded.rb +3 -0
  31. data/test/support/railtie/parent.rb +3 -0
  32. data/test/unit/associations/test_one_association.rb +18 -0
  33. data/test/unit/test_extensions.rb +4 -0
  34. data/test/unit/test_keys.rb +0 -22
  35. data/test/unit/test_plugins.rb +1 -46
  36. data/test/unit/test_railtie.rb +61 -0
  37. metadata +18 -14
  38. data/lib/mongo_mapper/support/descendant_appends.rb +0 -45
  39. data/test/functional/test_string_id_compatibility.rb +0 -75
  40. data/test/unit/test_descendant_appends.rb +0 -63
@@ -93,6 +93,144 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
93
93
  project.statuses[0].name.should == "ready"
94
94
  end
95
95
  end
96
+
97
+ context "with :dependent" do
98
+ setup do
99
+ @broker_class = Doc('Broker')
100
+ @property_class = Doc('Property') do
101
+ key :broker_id, ObjectId
102
+ belongs_to :broker
103
+ end
104
+ end
105
+
106
+ context "=> destroy" do
107
+ setup do
108
+ @broker_class.many :properties, :class => @property_class, :dependent => :destroy
109
+
110
+ @broker = @broker_class.create(:name => "Bob")
111
+ @property1 = @property_class.create
112
+ @property2 = @property_class.create
113
+ @property3 = @property_class.create
114
+ @broker.properties << @property1
115
+ @broker.properties << @property2
116
+ @broker.properties << @property3
117
+ end
118
+
119
+ should "call destroy the existing documents" do
120
+ @broker.properties[0].expects(:destroy).once
121
+ @broker.properties[1].expects(:destroy).once
122
+ @broker.properties[2].expects(:destroy).once
123
+ @broker.properties = [@property_class.new]
124
+ end
125
+
126
+ should "remove the existing document from the database" do
127
+ @property_class.count.should == 3
128
+ @broker.properties = []
129
+ @property_class.count.should == 0
130
+ end
131
+
132
+ should "skip over documents that are the same" do
133
+ @broker.properties[0].expects(:destroy).never
134
+ @broker.properties[1].expects(:destroy).once
135
+ @broker.properties[2].expects(:destroy).never
136
+ @broker.properties = [@property3, @property1]
137
+ end
138
+ end
139
+
140
+ context "=> delete_all" do
141
+ setup do
142
+ @broker_class.many :properties, :class => @property_class, :dependent => :delete_all
143
+
144
+ @broker = @broker_class.create(:name => "Bob")
145
+ @property1 = @property_class.create
146
+ @property2 = @property_class.create
147
+ @property3 = @property_class.create
148
+ @broker.properties << @property1
149
+ @broker.properties << @property2
150
+ @broker.properties << @property3
151
+ end
152
+
153
+ should "call delete the existing documents" do
154
+ @broker.properties[0].expects(:delete).once
155
+ @broker.properties[1].expects(:delete).once
156
+ @broker.properties[2].expects(:delete).once
157
+ @broker.properties = [@property_class.new]
158
+ end
159
+
160
+ should "remove the existing document from the database" do
161
+ @property_class.count.should == 3
162
+ @broker.properties = []
163
+ @property_class.count.should == 0
164
+ end
165
+
166
+ should "skip over documents that are the same" do
167
+ @broker.properties[0].expects(:delete).never
168
+ @broker.properties[1].expects(:delete).once
169
+ @broker.properties[2].expects(:delete).never
170
+ @broker.properties = [@property3, @property1]
171
+ end
172
+ end
173
+
174
+ context "=> nullify" do
175
+ setup do
176
+ @broker_class.many :properties, :class => @property_class, :dependent => :nullify
177
+
178
+ @broker = @broker_class.create(:name => "Bob")
179
+ @property1 = @property_class.create
180
+ @property2 = @property_class.create
181
+ @property3 = @property_class.create
182
+ @broker.properties << @property1
183
+ @broker.properties << @property2
184
+ @broker.properties << @property3
185
+ end
186
+
187
+ should "nullify the existing documents" do
188
+ @property1.reload.broker_id.should == @broker.id
189
+ @property2.reload.broker_id.should == @broker.id
190
+ @property3.reload.broker_id.should == @broker.id
191
+
192
+ @broker.properties = [@property_class.new]
193
+
194
+ @property1.reload.broker_id.should be_nil
195
+ @property2.reload.broker_id.should be_nil
196
+ @property3.reload.broker_id.should be_nil
197
+ end
198
+
199
+ should "skip over documents that are the same" do
200
+ @broker.properties = [@property3, @property1]
201
+
202
+ @property1.reload.broker_id.should == @broker.id
203
+ @property2.reload.broker_id.should be_nil
204
+ @property3.reload.broker_id.should == @broker.id
205
+ end
206
+
207
+ should "work" do
208
+ old_properties = @broker.properties
209
+ @broker.properties = [@property1, @property2, @property3]
210
+ old_properties.should == @broker.properties
211
+ end
212
+ end
213
+
214
+ context "unspecified" do
215
+ should "nullify the existing documents" do
216
+ @broker_class.many :properties, :class => @property_class
217
+
218
+ @broker = @broker_class.create(:name => "Bob")
219
+ @property1 = @property_class.create
220
+ @property2 = @property_class.create
221
+ @property3 = @property_class.create
222
+ @broker.properties << @property1
223
+ @broker.properties << @property2
224
+ @broker.properties << @property3
225
+
226
+ @broker.properties = [@property_class.new]
227
+
228
+ @property1.reload.broker_id.should be_nil
229
+ @property2.reload.broker_id.should be_nil
230
+ @property3.reload.broker_id.should be_nil
231
+ end
232
+ end
233
+ end
96
234
  end
97
235
 
98
236
  context "using <<, push and concat" do
@@ -624,6 +762,29 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
624
762
  Property.count.should == 3
625
763
  end
626
764
  end
765
+
766
+ context "unspecified" do
767
+ setup do
768
+ Property.key :thing_id, ObjectId
769
+ Property.belongs_to :thing
770
+ Thing.has_many :properties, :dependent => :nullify
771
+
772
+ @thing = Thing.create(:name => "Tree")
773
+ @property1 = Property.create
774
+ @property2 = Property.create
775
+ @property3 = Property.create
776
+ @thing.properties << @property1
777
+ @thing.properties << @property2
778
+ @thing.properties << @property3
779
+ end
780
+
781
+ should "should nullify relationship but not destroy associated documents" do
782
+ @thing.properties.count.should == 3
783
+ @thing.destroy
784
+ @thing.properties.count.should == 0
785
+ Property.count.should == 3
786
+ end
787
+ end
627
788
  end
628
789
 
629
790
  context "namespaced foreign keys" do
@@ -0,0 +1,485 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class OneAsProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ @post_class = Doc('Post')
7
+ @author_class = Doc('Author')
8
+ end
9
+
10
+ should "default to nil" do
11
+ @post_class.one :author, :as => :authorable, :class => @author_class
12
+ @post_class.new.author.nil?.should be_true
13
+ end
14
+
15
+ should "return nil instead of a proxy" do
16
+ @post_class.one :author, :as => :authorable, :class => @author_class
17
+ nil.should === @post_class.new.author
18
+ end
19
+
20
+ should "allow assignment of associated document using a hash" do
21
+ @post_class.one :author, :as => :authorable, :class => @author_class
22
+
23
+ post = @post_class.new('author' => { 'name' => 'Frank' })
24
+ post.author.name.should == 'Frank'
25
+
26
+ post.save.should be_true
27
+ post.reload
28
+
29
+ post.author.name.should == 'Frank'
30
+ end
31
+
32
+ should "only return a document with the correct type" do
33
+ @post_class.one :author, :as => :authorable, :class => @author_class
34
+ post = @post_class.create
35
+
36
+ author = @author_class.create(:authorable_id => post.id, :authorable_type => "Nada")
37
+ post.reload.author.should be_nil
38
+
39
+ author = @author_class.create(:authorable_id => post.id, :authorable_type => "Post")
40
+ post.reload.author.should == author
41
+ end
42
+
43
+ context "replacing the association" do
44
+ context "with an object of the class" do
45
+ setup do
46
+ @post_class.one :author, :as => :authorable, :class => @author_class
47
+ @post = @post_class.new
48
+ @author = @author_class.new(:name => 'Frank')
49
+ end
50
+
51
+ should "work" do
52
+ @post.author = @author
53
+ @post.reload
54
+
55
+ @post.author.should == @author
56
+ @post.author.nil?.should be_false
57
+
58
+ new_author = @author_class.new(:name => 'Emily')
59
+ @post.author = new_author
60
+ @post.author.should == new_author
61
+ end
62
+
63
+ should "generate a new proxy instead of modifying the existing one" do
64
+ @post.author = @author
65
+ @post.reload
66
+
67
+ @post.author.should == @author
68
+ @post.author.nil?.should be_false
69
+
70
+ original_author = @post.author
71
+ original_author.name.should == 'Frank'
72
+ new_author = @author_class.new(:name => 'Emily')
73
+ @post.author = new_author
74
+ @post.author.should == new_author
75
+
76
+ original_author.name.should == 'Frank'
77
+ end
78
+
79
+ should "assign foreign key" do
80
+ @post.author = @author
81
+ @post.author.authorable_id.should == @post.id
82
+ end
83
+
84
+ should "assign _type" do
85
+ @post.author = @author
86
+ @post.author.authorable_type.should == "Post"
87
+ end
88
+ end
89
+
90
+ context "with a Hash" do
91
+ setup do
92
+ @post_class.one :author, :as => :authorable, :class => @author_class
93
+ @post = @post_class.new
94
+ end
95
+
96
+ should "convert to an object of the class and work" do
97
+ @post.author = {'name' => 'Frank'}
98
+ @post.reload
99
+
100
+ @post.author.name.should == 'Frank'
101
+ @post.author.nil?.should be_false
102
+
103
+ @post.author = {'name' => 'Emily'}
104
+ @post.author.name.should == 'Emily'
105
+ end
106
+
107
+ should "assign foreign key" do
108
+ @post.author = {'name' => 'Frank'}
109
+ @post.author.authorable_id.should == @post.id
110
+ end
111
+
112
+ should "assign _type" do
113
+ @post.author = {'name' => 'Frank'}
114
+ @post.author.authorable_type.should == "Post"
115
+ end
116
+ end
117
+
118
+ context "with :dependent" do
119
+ context "=> delete" do
120
+ setup do
121
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :delete
122
+
123
+ @post = @post_class.create
124
+ @author = @author_class.new
125
+ @post.author = @author
126
+ end
127
+
128
+ should "call delete on the existing document" do
129
+ @author_class.any_instance.expects(:delete).once
130
+ @post.author = @author_class.new
131
+ end
132
+
133
+ should "remove the existing document from the database" do
134
+ @post.author = @author_class.new
135
+ lambda { @author.reload }.should raise_error(MongoMapper::DocumentNotFound)
136
+ end
137
+
138
+ should "do nothing if it's the same document" do
139
+ @author_class.any_instance.expects(:delete).never
140
+ @post.author = @author
141
+ end
142
+ end
143
+
144
+ context "=> destory" do
145
+ setup do
146
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :destroy
147
+
148
+ @post = @post_class.create
149
+ @author = @author_class.new
150
+ @post.author = @author
151
+ end
152
+
153
+ should "call destroy the existing document" do
154
+ @author_class.any_instance.expects(:destroy).once
155
+ @post.author = @author_class.new
156
+ end
157
+
158
+ should "remove the existing document from the database" do
159
+ @post.author = @author_class.new
160
+ lambda { @author.reload }.should raise_error(MongoMapper::DocumentNotFound)
161
+ end
162
+
163
+ should "do nothing if it's the same document" do
164
+ @author_class.any_instance.expects(:destroy).never
165
+ @post.author = @author
166
+ end
167
+ end
168
+
169
+ context "=> nullify" do
170
+ setup do
171
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :nullify
172
+
173
+ @post = @post_class.create
174
+ @author = @author_class.new
175
+ @post.author = @author
176
+ end
177
+
178
+ should "nullify the existing document" do
179
+ @author.reload
180
+ @author.authorable_id.should == @post.id
181
+
182
+ @post.author = @author_class.new
183
+
184
+ @author.reload
185
+ @author.authorable_id.should be_nil
186
+ end
187
+
188
+ should "work when it's the same document" do
189
+ old_author = @post.author
190
+ @post.author = @author
191
+ old_author.should == @post.author
192
+ end
193
+
194
+ should "nullify _type" do
195
+ @post.author = @author_class.new
196
+ @author.reload
197
+ @author.authorable_type.should be_nil
198
+ end
199
+ end
200
+
201
+ context "unspecified" do
202
+ setup do
203
+ @post_class.one :author, :as => :authorable, :class => @author_class
204
+
205
+ @post = @post_class.create
206
+ @author = @author_class.new
207
+ @post.author = @author
208
+ end
209
+
210
+ should "nullify the existing document" do
211
+ @author.reload
212
+ @author.authorable_id.should == @post.id
213
+
214
+ @post.author = @author_class.new
215
+
216
+ @author.reload
217
+ @author.authorable_id.should be_nil
218
+ end
219
+
220
+ should "nullify _type" do
221
+ @post.author = @author_class.new
222
+ @author.reload
223
+ @author.authorable_type.should be_nil
224
+ end
225
+ end
226
+ end
227
+
228
+ context "with nil" do
229
+ setup do
230
+ @post_class.one :author, :as => :authorable, :class => @author_class
231
+
232
+ @post = @post_class.new
233
+ @author = @author_class.new(:name => 'Frank')
234
+ @post.author = @author
235
+ end
236
+
237
+ should "nullify the existing document" do
238
+ @post.author = nil
239
+ @author.reload
240
+ @author.authorable_id.should be_nil
241
+ end
242
+
243
+ should "set the target to nil" do
244
+ @post.author = nil
245
+ @post.author.should == nil
246
+ end
247
+
248
+ should "nullify _type" do
249
+ @post.author = nil
250
+ @author.reload
251
+ @author.authorable_type.should be_nil
252
+ end
253
+ end
254
+ end
255
+
256
+ should "have boolean method for testing presence" do
257
+ @post_class.one :author, :as => :authorable, :class => @author_class
258
+
259
+ post = @post_class.new
260
+ post.author?.should be_false
261
+
262
+ post.author = @author_class.new(:name => 'Frank')
263
+ post.author?.should be_true
264
+ end
265
+
266
+ should "work with criteria" do
267
+ @post_class.one :primary_author, :as => :authorable, :class => @author_class, :primary => true
268
+ @post_class.one :author, :as => :authorable, :class => @author_class, :primary => false
269
+
270
+ post = @post_class.create
271
+ author = @author_class.create(:name => 'Frank', :primary => false, :authorable_id => post.id, :authorable_type => 'Post')
272
+ primary = @author_class.create(:name => 'Bill', :primary => true, :authorable_id => post.id, :authorable_type => 'Post')
273
+ post.reload
274
+ post.author.should == author
275
+ post.primary_author.should == primary
276
+ end
277
+
278
+ should "unset the association" do
279
+ @post_class.one :author, :as => :authorable, :class => @author_class
280
+ post = @post_class.create
281
+ author = @author_class.create
282
+ post.update_attributes!(:author => author)
283
+ post.reload
284
+ post.author = nil
285
+ post.author.nil?.should be_true
286
+ end
287
+
288
+ context "destroying parent with :dependent" do
289
+ context "=> destroy" do
290
+ setup do
291
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :destroy
292
+
293
+ @post = @post_class.create
294
+ @author = @author_class.new
295
+ @post.author = @author
296
+ end
297
+
298
+ should "should call destroy on the associated documents" do
299
+ @author_class.any_instance.expects(:destroy).once
300
+ @post.destroy
301
+ end
302
+
303
+ should "should remove the associated documents" do
304
+ @author_class.count.should == 1
305
+ @post.destroy
306
+ @post.author.should == nil
307
+ @author_class.count.should == 0
308
+ end
309
+ end
310
+
311
+ context "=> delete" do
312
+ setup do
313
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :delete
314
+
315
+ @post = @post_class.create
316
+ @author = @author_class.new
317
+ @post.author = @author
318
+ end
319
+
320
+ should "should call delete the associated documents" do
321
+ @author_class.any_instance.expects(:delete).once
322
+ @post.destroy
323
+ end
324
+
325
+ should "remove the associated documents" do
326
+ @author_class.count.should == 1
327
+ @post.destroy
328
+ @post.author.should == nil
329
+ @author_class.count.should == 0
330
+ end
331
+ end
332
+
333
+ context "=> nullify" do
334
+ setup do
335
+ @post_class.one :author, :as => :authorable, :class => @author_class, :dependent => :nullify
336
+
337
+ @post = @post_class.create
338
+ @author = @author_class.new
339
+ @post.author = @author
340
+ end
341
+
342
+ should "should nullify the relationship but not destroy the associated document" do
343
+ @author_class.count.should == 1
344
+ @post.destroy
345
+ @post.author.should == nil
346
+ @author_class.count.should == 1
347
+
348
+ @author_class.first.should == @author
349
+ @author.authorable_id.should == nil
350
+ end
351
+
352
+ should "nullify _type" do
353
+ @post.destroy
354
+ @author.authorable_type.should be_nil
355
+ end
356
+ end
357
+
358
+ context "unspecified" do
359
+ setup do
360
+ @post_class.one :author, :as => :authorable, :class => @author_class
361
+
362
+ @post = @post_class.create
363
+ @author = @author_class.new
364
+ @post.author = @author
365
+ end
366
+
367
+ should "should nullify the relationship but not destroy the associated document" do
368
+ @author_class.count.should == 1
369
+ @post.destroy
370
+ @post.author.should == nil
371
+ @author_class.count.should == 1
372
+
373
+ @author_class.first.should == @author
374
+ @author.authorable_id.should == nil
375
+ end
376
+
377
+ should "nullify _type" do
378
+ @post.destroy
379
+ @author.authorable_type.should be_nil
380
+ end
381
+ end
382
+ end
383
+
384
+ context "#build" do
385
+ setup do
386
+ @post_class.one :author, :as => :authorable, :class => @author_class
387
+ @post = @post_class.create
388
+ end
389
+
390
+ should "be able to build with attributes" do
391
+ author = @post.build_author(:name => 'John')
392
+ @post.author.should be_instance_of(@author_class)
393
+ @post.author.should be_new
394
+ @post.author.name.should == 'John'
395
+ @post.author.should == author
396
+ end
397
+
398
+ should "assign foreign key" do
399
+ @post.build_author
400
+ @post.author.authorable_id.should == @post.id
401
+ end
402
+
403
+ should "assign _type" do
404
+ @post.build_author
405
+ @post.author.authorable_type.should == 'Post'
406
+ end
407
+ end
408
+
409
+ context "#create" do
410
+ setup do
411
+ @post_class.one :author, :as => :authorable, :class => @author_class
412
+ @post = @post_class.create
413
+ end
414
+
415
+ should "be able to create" do
416
+ author = @post.create_author(:name => 'John')
417
+ @post.author.should be_instance_of(@author_class)
418
+ @post.author.should_not be_new
419
+ @post.author.name.should == 'John'
420
+ @post.author.should == author
421
+ end
422
+
423
+ should "assign foreign key" do
424
+ @post.create_author
425
+ @post.author.authorable_id.should == @post.id
426
+ end
427
+
428
+ should "assign _type" do
429
+ @post.create_author
430
+ @post.author.authorable_type.should == 'Post'
431
+ end
432
+ end
433
+
434
+ context "#create!" do
435
+ setup do
436
+ @author_class.key :name, String, :required => true
437
+ @post_class.one :author, :as => :authorable, :class => @author_class
438
+ @post = @post_class.create
439
+ end
440
+
441
+ should "raise exception if invalid" do
442
+ assert_raises(MongoMapper::DocumentNotValid) do
443
+ @post.create_author!
444
+ end
445
+ end
446
+
447
+ should "work if valid" do
448
+ author = @post.create_author!(:name => 'John')
449
+ @post.author.should be_instance_of(@author_class)
450
+ @post.author.should_not be_new
451
+ @post.author.name.should == 'John'
452
+ @post.author.should == author
453
+ end
454
+
455
+ should "assign foreign key if valid" do
456
+ @post.create_author!(:name => 'John')
457
+ @post.author.authorable_id.should == @post.id
458
+ end
459
+
460
+ should "assign _type if valid" do
461
+ @post.create_author!(:name => 'John')
462
+ @post.author.authorable_type.should == 'Post'
463
+ end
464
+ end
465
+
466
+ context "namespaced foreign keys" do
467
+ setup do
468
+ News::Paper.one :article, :as => 'articleable', :class_name => 'News::Article'
469
+ News::Article.belongs_to :articleable, :polymorphic => true
470
+
471
+ @paper = News::Paper.create
472
+ end
473
+
474
+ should "work" do
475
+ @paper.create_article
476
+ @paper.article.class.should == News::Article
477
+ end
478
+
479
+ should "properly infer the foreign key" do
480
+ article = @paper.create_article
481
+ article.should respond_to(:articleable_id)
482
+ article.articleable_id.should == @paper.id
483
+ end
484
+ end
485
+ end