ign-mongo_mapper 0.8.6.1

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 (147) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +7 -0
  4. data/bin/mmconsole +60 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +8 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +41 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +83 -0
  19. data/lib/mongo_mapper/connection.rb +83 -0
  20. data/lib/mongo_mapper/document.rb +41 -0
  21. data/lib/mongo_mapper/embedded_document.rb +31 -0
  22. data/lib/mongo_mapper/exceptions.rb +27 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +27 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +30 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +29 -0
  37. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  38. data/lib/mongo_mapper/plugins.rb +15 -0
  39. data/lib/mongo_mapper/plugins/accessible.rb +44 -0
  40. data/lib/mongo_mapper/plugins/associations.rb +134 -0
  41. data/lib/mongo_mapper/plugins/associations/base.rb +124 -0
  42. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +29 -0
  43. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +24 -0
  44. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  45. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +40 -0
  46. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +151 -0
  47. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  48. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +109 -0
  49. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  50. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  51. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  52. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +41 -0
  53. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  54. data/lib/mongo_mapper/plugins/associations/proxy.rb +139 -0
  55. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  56. data/lib/mongo_mapper/plugins/callbacks.rb +243 -0
  57. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  58. data/lib/mongo_mapper/plugins/descendants.rb +17 -0
  59. data/lib/mongo_mapper/plugins/dirty.rb +124 -0
  60. data/lib/mongo_mapper/plugins/document.rb +41 -0
  61. data/lib/mongo_mapper/plugins/dynamic_querying.rb +43 -0
  62. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  63. data/lib/mongo_mapper/plugins/embedded_document.rb +48 -0
  64. data/lib/mongo_mapper/plugins/equality.rb +17 -0
  65. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  66. data/lib/mongo_mapper/plugins/indexes.rb +12 -0
  67. data/lib/mongo_mapper/plugins/inspect.rb +15 -0
  68. data/lib/mongo_mapper/plugins/keys.rb +311 -0
  69. data/lib/mongo_mapper/plugins/keys/key.rb +65 -0
  70. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  71. data/lib/mongo_mapper/plugins/modifiers.rb +112 -0
  72. data/lib/mongo_mapper/plugins/pagination.rb +14 -0
  73. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  74. data/lib/mongo_mapper/plugins/protected.rb +53 -0
  75. data/lib/mongo_mapper/plugins/querying.rb +176 -0
  76. data/lib/mongo_mapper/plugins/querying/decorator.rb +46 -0
  77. data/lib/mongo_mapper/plugins/querying/plucky_methods.rb +15 -0
  78. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  79. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  80. data/lib/mongo_mapper/plugins/sci.rb +32 -0
  81. data/lib/mongo_mapper/plugins/scopes.rb +21 -0
  82. data/lib/mongo_mapper/plugins/serialization.rb +76 -0
  83. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  84. data/lib/mongo_mapper/plugins/userstamps.rb +15 -0
  85. data/lib/mongo_mapper/plugins/validations.rb +50 -0
  86. data/lib/mongo_mapper/support/descendant_appends.rb +45 -0
  87. data/lib/mongo_mapper/version.rb +4 -0
  88. data/rails/init.rb +15 -0
  89. data/test/_NOTE_ON_TESTING +1 -0
  90. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  91. data/test/functional/associations/test_belongs_to_proxy.rb +117 -0
  92. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  93. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  94. data/test/functional/associations/test_many_documents_proxy.rb +615 -0
  95. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  96. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  97. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  98. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  99. data/test/functional/associations/test_one_proxy.rb +206 -0
  100. data/test/functional/test_accessible.rb +168 -0
  101. data/test/functional/test_associations.rb +46 -0
  102. data/test/functional/test_binary.rb +27 -0
  103. data/test/functional/test_caching.rb +76 -0
  104. data/test/functional/test_callbacks.rb +151 -0
  105. data/test/functional/test_dirty.rb +163 -0
  106. data/test/functional/test_document.rb +272 -0
  107. data/test/functional/test_dynamic_querying.rb +75 -0
  108. data/test/functional/test_embedded_document.rb +210 -0
  109. data/test/functional/test_identity_map.rb +513 -0
  110. data/test/functional/test_indexes.rb +42 -0
  111. data/test/functional/test_logger.rb +20 -0
  112. data/test/functional/test_modifiers.rb +416 -0
  113. data/test/functional/test_pagination.rb +91 -0
  114. data/test/functional/test_protected.rb +175 -0
  115. data/test/functional/test_querying.rb +873 -0
  116. data/test/functional/test_safe.rb +76 -0
  117. data/test/functional/test_sci.rb +230 -0
  118. data/test/functional/test_scopes.rb +171 -0
  119. data/test/functional/test_string_id_compatibility.rb +67 -0
  120. data/test/functional/test_timestamps.rb +62 -0
  121. data/test/functional/test_userstamps.rb +27 -0
  122. data/test/functional/test_validations.rb +342 -0
  123. data/test/models.rb +233 -0
  124. data/test/test_active_model_lint.rb +13 -0
  125. data/test/test_helper.rb +102 -0
  126. data/test/unit/associations/test_base.rb +212 -0
  127. data/test/unit/associations/test_proxy.rb +105 -0
  128. data/test/unit/serializers/test_json_serializer.rb +217 -0
  129. data/test/unit/test_clone.rb +69 -0
  130. data/test/unit/test_descendant_appends.rb +71 -0
  131. data/test/unit/test_document.rb +208 -0
  132. data/test/unit/test_dynamic_finder.rb +125 -0
  133. data/test/unit/test_embedded_document.rb +639 -0
  134. data/test/unit/test_extensions.rb +376 -0
  135. data/test/unit/test_identity_map_middleware.rb +34 -0
  136. data/test/unit/test_inspect.rb +22 -0
  137. data/test/unit/test_key.rb +205 -0
  138. data/test/unit/test_keys.rb +89 -0
  139. data/test/unit/test_mongo_mapper.rb +110 -0
  140. data/test/unit/test_pagination.rb +11 -0
  141. data/test/unit/test_plugins.rb +50 -0
  142. data/test/unit/test_rails.rb +181 -0
  143. data/test/unit/test_rails_compatibility.rb +52 -0
  144. data/test/unit/test_serialization.rb +51 -0
  145. data/test/unit/test_time_zones.rb +39 -0
  146. data/test/unit/test_validations.rb +564 -0
  147. metadata +385 -0
@@ -0,0 +1,615 @@
1
+ require 'test_helper.rb'
2
+ require 'models'
3
+
4
+ class ManyDocumentsProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Project.collection.remove
7
+ Status.collection.remove
8
+
9
+ @pet_class = Doc do
10
+ key :name, String
11
+ key :owner_id, ObjectId
12
+ end
13
+
14
+ @owner_class = Doc do
15
+ key :name, String
16
+ end
17
+ @owner_class.many :pets, :class => @pet_class, :foreign_key => :owner_id, :order => 'name'
18
+ end
19
+
20
+ should "default reader to empty array" do
21
+ project = Project.new
22
+ project.statuses.should == []
23
+ end
24
+
25
+ should "allow assignment of many associated documents using a hash" do
26
+ person_attributes = {
27
+ 'name' => 'Mr. Pet Lover',
28
+ 'pets' => [
29
+ {'name' => 'Jimmy', 'species' => 'Cocker Spainel'},
30
+ {'name' => 'Sasha', 'species' => 'Siberian Husky'},
31
+ ]
32
+ }
33
+
34
+ owner = @owner_class.new(person_attributes)
35
+ owner.name.should == 'Mr. Pet Lover'
36
+ owner.pets[0].name.should == 'Jimmy'
37
+ owner.pets[0].species.should == 'Cocker Spainel'
38
+ owner.pets[1].name.should == 'Sasha'
39
+ owner.pets[1].species.should == 'Siberian Husky'
40
+
41
+ owner.save.should be_true
42
+ owner.reload
43
+
44
+ owner.name.should == 'Mr. Pet Lover'
45
+ owner.pets[0].name.should == 'Jimmy'
46
+ owner.pets[0].species.should == 'Cocker Spainel'
47
+ owner.pets[1].name.should == 'Sasha'
48
+ owner.pets[1].species.should == 'Siberian Husky'
49
+ end
50
+
51
+ should "allow adding to association like it was an array" do
52
+ project = Project.new
53
+ project.statuses << Status.new(:name => 'Foo1!')
54
+ project.statuses.push Status.new(:name => 'Foo2!')
55
+ project.statuses.concat Status.new(:name => 'Foo3!')
56
+ project.statuses.size.should == 3
57
+ end
58
+
59
+ context "replacing the association" do
60
+ context "with objects of the class" do
61
+ should "work" do
62
+ project = Project.new
63
+ project.statuses = [Status.new(:name => "ready")]
64
+ project.save.should be_true
65
+
66
+ project.reload
67
+ project.statuses.size.should == 1
68
+ project.statuses[0].name.should == "ready"
69
+ end
70
+ end
71
+
72
+ context "with Hashes" do
73
+ should "convert to objects of the class and work" do
74
+ project = Project.new
75
+ project.statuses = [{ 'name' => 'ready' }]
76
+ project.save.should be_true
77
+
78
+ project.reload
79
+ project.statuses.size.should == 1
80
+ project.statuses[0].name.should == "ready"
81
+ end
82
+ end
83
+ end
84
+
85
+ context "using <<, push and concat" do
86
+ context "with objects of the class" do
87
+ should "correctly assign foreign key" do
88
+ project = Project.new
89
+ project.statuses << Status.new(:name => '<<')
90
+ project.statuses.push Status.new(:name => 'push')
91
+ project.statuses.concat Status.new(:name => 'concat')
92
+
93
+ project.reload
94
+ project.statuses[0].project_id.should == project.id
95
+ project.statuses[1].project_id.should == project.id
96
+ project.statuses[2].project_id.should == project.id
97
+ end
98
+ end
99
+
100
+ context "with Hashes" do
101
+ should "correctly convert to objects and assign foreign key" do
102
+ project = Project.new
103
+ project.statuses << { 'name' => '<<' }
104
+ project.statuses.push( { 'name' => 'push' })
105
+ project.statuses.concat({ 'name' => 'concat' })
106
+
107
+ project.reload
108
+ project.statuses[0].project_id.should == project.id
109
+ project.statuses[1].project_id.should == project.id
110
+ project.statuses[2].project_id.should == project.id
111
+ end
112
+ end
113
+ end
114
+
115
+ context "build" do
116
+ should "assign foreign key" do
117
+ project = Project.create
118
+ status = project.statuses.build
119
+ status.project_id.should == project.id
120
+ end
121
+
122
+ should "allow assigning attributes" do
123
+ project = Project.create
124
+ status = project.statuses.build(:name => 'Foo')
125
+ status.name.should == 'Foo'
126
+ end
127
+
128
+ should "reset cache" do
129
+ project = Project.create
130
+ project.statuses.size.should == 0
131
+ status = project.statuses.build(:name => 'Foo')
132
+ status.save!
133
+ project.statuses.size.should == 1
134
+ end
135
+
136
+ should "update collection without save" do
137
+ project = Project.create
138
+ project.statuses.build(:name => 'Foo')
139
+ project.statuses.size.should == 1
140
+ end
141
+
142
+ should "save built document when saving parent" do
143
+ project = Project.create
144
+ status = project.statuses.build(:name => 'Foo')
145
+ project.save!
146
+ status.should_not be_new
147
+ end
148
+
149
+ should "not save the parent when building associations" do
150
+ project = Project.new
151
+ status = project.statuses.build(:name => 'Foo')
152
+ project.should be_new
153
+ end
154
+
155
+ should "not save the built object" do
156
+ project = Project.new
157
+ status = project.statuses.build(:name => 'Foo')
158
+ status.should be_new
159
+ end
160
+ end
161
+
162
+ context "create" do
163
+ should "assign foreign key" do
164
+ project = Project.create
165
+ status = project.statuses.create(:name => 'Foo!')
166
+ status.project_id.should == project.id
167
+ end
168
+
169
+ should "save record" do
170
+ project = Project.create
171
+ lambda {
172
+ project.statuses.create(:name => 'Foo!')
173
+ }.should change { Status.count }
174
+ end
175
+
176
+ should "allow passing attributes" do
177
+ project = Project.create
178
+ status = project.statuses.create(:name => 'Foo!')
179
+ status.name.should == 'Foo!'
180
+ end
181
+
182
+ should "reset cache" do
183
+ project = Project.create
184
+ project.statuses.size.should == 0
185
+ project.statuses.create(:name => 'Foo!')
186
+ project.statuses.size.should == 1
187
+ end
188
+ end
189
+
190
+ context "create!" do
191
+ should "assign foreign key" do
192
+ project = Project.create
193
+ status = project.statuses.create!(:name => 'Foo!')
194
+ status.project_id.should == project.id
195
+ end
196
+
197
+ should "save record" do
198
+ project = Project.create
199
+ lambda {
200
+ project.statuses.create!(:name => 'Foo!')
201
+ }.should change { Status.count }
202
+ end
203
+
204
+ should "allow passing attributes" do
205
+ project = Project.create
206
+ status = project.statuses.create!(:name => 'Foo!')
207
+ status.name.should == 'Foo!'
208
+ end
209
+
210
+ should "raise exception if not valid" do
211
+ project = Project.create
212
+ lambda {
213
+ project.statuses.create!(:name => nil)
214
+ }.should raise_error(MongoMapper::DocumentNotValid)
215
+ end
216
+
217
+ should "reset cache" do
218
+ project = Project.create
219
+ project.statuses.size.should == 0
220
+ project.statuses.create!(:name => 'Foo!')
221
+ project.statuses.size.should == 1
222
+ end
223
+ end
224
+
225
+ context "count" do
226
+ should "work scoped to association" do
227
+ project = Project.create
228
+ 3.times { project.statuses.create(:name => 'Foo!') }
229
+
230
+ other_project = Project.create
231
+ 2.times { other_project.statuses.create(:name => 'Foo!') }
232
+
233
+ project.statuses.count.should == 3
234
+ other_project.statuses.count.should == 2
235
+ end
236
+
237
+ should "work with conditions" do
238
+ project = Project.create
239
+ project.statuses.create(:name => 'Foo')
240
+ project.statuses.create(:name => 'Other 1')
241
+ project.statuses.create(:name => 'Other 2')
242
+
243
+ project.statuses.count(:name => 'Foo').should == 1
244
+ end
245
+ end
246
+
247
+ context "to_json" do
248
+ should "work on association" do
249
+ project = Project.create
250
+ 3.times { |i| project.statuses.create(:name => i.to_s) }
251
+
252
+ JSON.parse(project.statuses.to_json).collect{|status| status["name"] }.sort.should == ["0","1","2"]
253
+ end
254
+ end
255
+
256
+ context "as_json" do
257
+ should "work on association" do
258
+ project = Project.create
259
+ 3.times { |i| project.statuses.create(:name => i.to_s) }
260
+
261
+ project.statuses.as_json.collect{|status| status["name"] }.sort.should == ["0","1","2"]
262
+ end
263
+ end
264
+
265
+ context "Unassociating documents" do
266
+ setup do
267
+ @project = Project.create
268
+ @project.statuses << Status.create(:name => '1')
269
+ @project.statuses << Status.create(:name => '2')
270
+
271
+ @project2 = Project.create
272
+ @project2.statuses << Status.create(:name => '1')
273
+ @project2.statuses << Status.create(:name => '2')
274
+ end
275
+
276
+ should "work with destroy all" do
277
+ @project.statuses.count.should == 2
278
+ @project.statuses.destroy_all
279
+ @project.statuses.count.should == 0
280
+
281
+ @project2.statuses.count.should == 2
282
+ Status.count.should == 2
283
+ end
284
+
285
+ should "work with destroy all and conditions" do
286
+ @project.statuses.count.should == 2
287
+ @project.statuses.destroy_all(:name => '1')
288
+ @project.statuses.count.should == 1
289
+
290
+ @project2.statuses.count.should == 2
291
+ Status.count.should == 3
292
+ end
293
+
294
+ should "work with delete all" do
295
+ @project.statuses.count.should == 2
296
+ @project.statuses.delete_all
297
+ @project.statuses.count.should == 0
298
+
299
+ @project2.statuses.count.should == 2
300
+ Status.count.should == 2
301
+ end
302
+
303
+ should "work with delete all and conditions" do
304
+ @project.statuses.count.should == 2
305
+ @project.statuses.delete_all(:name => '1')
306
+ @project.statuses.count.should == 1
307
+
308
+ @project2.statuses.count.should == 2
309
+ Status.count.should == 3
310
+ end
311
+
312
+ should "work with nullify" do
313
+ @project.statuses.count.should == 2
314
+ @project.statuses.nullify
315
+ @project.statuses.count.should == 0
316
+
317
+ @project2.statuses.count.should == 2
318
+ Status.count.should == 4
319
+ Status.count(:name => '1').should == 2
320
+ Status.count(:name => '2').should == 2
321
+ end
322
+ end
323
+
324
+ context "Finding scoped to association" do
325
+ setup do
326
+ @project1 = Project.new(:name => 'Project 1')
327
+ @brand_new = Status.create(:name => 'New', :position => 1 )
328
+ @complete = Status.create(:name => 'Complete', :position => 2)
329
+ @project1.statuses = [@brand_new, @complete]
330
+ @project1.save
331
+
332
+ @project2 = Project.create(:name => 'Project 2')
333
+ @in_progress = Status.create(:name => 'In Progress')
334
+ @archived = Status.create(:name => 'Archived')
335
+ @another_complete = Status.create(:name => 'Complete')
336
+ @project2.statuses = [@in_progress, @archived, @another_complete]
337
+ @project2.save
338
+ end
339
+
340
+ context "include?" do
341
+ should "return true if in association" do
342
+ @project1.statuses.should include(@brand_new)
343
+ end
344
+
345
+ should "return false if not in association" do
346
+ @project1.statuses.should_not include(@in_progress)
347
+ end
348
+ end
349
+
350
+ context "dynamic finders" do
351
+ should "work with single key" do
352
+ @project1.statuses.find_by_name('New').should == @brand_new
353
+ @project1.statuses.find_by_name!('New').should == @brand_new
354
+ @project2.statuses.find_by_name('In Progress').should == @in_progress
355
+ @project2.statuses.find_by_name!('In Progress').should == @in_progress
356
+ end
357
+
358
+ should "work with multiple keys" do
359
+ @project1.statuses.find_by_name_and_position('New', 1).should == @brand_new
360
+ @project1.statuses.find_by_name_and_position!('New', 1).should == @brand_new
361
+ @project1.statuses.find_by_name_and_position('New', 2).should be_nil
362
+ end
363
+
364
+ should "raise error when using !" do
365
+ lambda {
366
+ @project1.statuses.find_by_name!('Fake')
367
+ }.should raise_error(MongoMapper::DocumentNotFound)
368
+ end
369
+
370
+ context "find_or_create_by" do
371
+ should "not create document if found" do
372
+ lambda {
373
+ status = @project1.statuses.find_or_create_by_name('New')
374
+ status.project.should == @project1
375
+ status.should == @brand_new
376
+ }.should_not change { Status.count }
377
+ end
378
+
379
+ should "create document if not found" do
380
+ lambda {
381
+ status = @project1.statuses.find_or_create_by_name('Delivered')
382
+ status.project.should == @project1
383
+ }.should change { Status.count }
384
+ end
385
+ end
386
+ end
387
+
388
+ context "sexy querying" do
389
+ should "work with where" do
390
+ @project1.statuses.where(:name => 'New').all.should == [@brand_new]
391
+ end
392
+
393
+ should "work with sort" do
394
+ @project1.statuses.sort(:name).all.should == [@complete, @brand_new]
395
+ end
396
+
397
+ should "work with limit" do
398
+ @project1.statuses.sort(:name).limit(1).all.should == [@complete]
399
+ end
400
+
401
+ should "work with skip" do
402
+ @project1.statuses.sort(:name).skip(1).all.should == [@brand_new]
403
+ end
404
+
405
+ should "work with fields" do
406
+ @project1.statuses.fields(:position).all.each do |status|
407
+ status.position.should_not be_nil
408
+ status.name.should be_nil
409
+ end
410
+ end
411
+
412
+ should "work with scopes" do
413
+ @project1.statuses.complete.all.should == [@complete]
414
+ end
415
+
416
+ should "work with methods on class that return query" do
417
+ @project1.statuses.by_position(1).first.should == @brand_new
418
+ end
419
+
420
+ should "not work with methods on class that do not return query" do
421
+ Status.class_eval { def self.foo; 'foo' end }
422
+ lambda { @project1.statuses.foo }.
423
+ should raise_error(NoMethodError)
424
+ end
425
+ end
426
+
427
+ context "all" do
428
+ should "work" do
429
+ @project1.statuses.all(:order => "position asc").should == [@brand_new, @complete]
430
+ end
431
+
432
+ should "work with conditions" do
433
+ @project1.statuses.all(:name => 'Complete').should == [@complete]
434
+ end
435
+ end
436
+
437
+ context "first" do
438
+ should "work" do
439
+ @project1.statuses.first(:order => 'name').should == @complete
440
+ end
441
+
442
+ should "work with conditions" do
443
+ @project1.statuses.first(:name => 'Complete').should == @complete
444
+ end
445
+ end
446
+
447
+ context "last" do
448
+ should "work" do
449
+ @project1.statuses.last(:order => "position asc").should == @complete
450
+ end
451
+
452
+ should "work with conditions" do
453
+ @project1.statuses.last(:order => 'position', :name => 'New').should == @brand_new
454
+ end
455
+ end
456
+
457
+ context "with one id" do
458
+ should "work for id in association" do
459
+ @project1.statuses.find(@complete.id).should == @complete
460
+ end
461
+
462
+ should "not work for id not in association" do
463
+ lambda {
464
+ @project1.statuses.find!(@archived.id)
465
+ }.should raise_error(MongoMapper::DocumentNotFound)
466
+ end
467
+ end
468
+
469
+ context "with multiple ids" do
470
+ should "work for ids in association" do
471
+ statuses = @project1.statuses.find(@brand_new.id, @complete.id)
472
+ statuses.should == [@brand_new, @complete]
473
+ end
474
+
475
+ should "not work for ids not in association" do
476
+ assert_raises(MongoMapper::DocumentNotFound) do
477
+ @project1.statuses.find!(@brand_new.id, @complete.id, @archived.id)
478
+ end
479
+ end
480
+ end
481
+
482
+ context "with #paginate" do
483
+ setup do
484
+ @statuses = @project2.statuses.paginate(:per_page => 2, :page => 1, :order => 'name asc')
485
+ end
486
+
487
+ should "return total pages" do
488
+ @statuses.total_pages.should == 2
489
+ end
490
+
491
+ should "return total entries" do
492
+ @statuses.total_entries.should == 3
493
+ end
494
+
495
+ should "return the subject" do
496
+ @statuses.collect(&:name).should == %w(Archived Complete)
497
+ end
498
+ end
499
+ end
500
+
501
+ context "extending the association" do
502
+ should "work using a block passed to many" do
503
+ project = Project.new(:name => "Some Project")
504
+ status1 = Status.new(:name => "New")
505
+ status2 = Status.new(:name => "Assigned")
506
+ status3 = Status.new(:name => "Closed")
507
+ project.statuses = [status1, status2, status3]
508
+ project.save
509
+
510
+ open_statuses = project.statuses.open
511
+ open_statuses.should include(status1)
512
+ open_statuses.should include(status2)
513
+ open_statuses.should_not include(status3)
514
+ end
515
+
516
+ should "work using many's :extend option" do
517
+ project = Project.new(:name => "Some Project")
518
+ collaborator1 = Collaborator.new(:name => "zing")
519
+ collaborator2 = Collaborator.new(:name => "zang")
520
+ project.collaborators = [collaborator1, collaborator2]
521
+ project.save
522
+ project.collaborators.top.should == collaborator1
523
+ end
524
+ end
525
+
526
+ context ":dependent" do
527
+ setup do
528
+ # FIXME: make use of already defined models
529
+ class ::Property
530
+ include MongoMapper::Document
531
+ end
532
+ Property.collection.remove
533
+
534
+ class ::Thing
535
+ include MongoMapper::Document
536
+ key :name, String
537
+ end
538
+ Thing.collection.remove
539
+ end
540
+
541
+ teardown do
542
+ Object.send :remove_const, 'Property' if defined?(::Property)
543
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
544
+ end
545
+
546
+ context "=> destroy" do
547
+ setup do
548
+ Property.key :thing_id, ObjectId
549
+ Property.belongs_to :thing, :dependent => :destroy
550
+ Thing.many :properties, :dependent => :destroy
551
+
552
+ @thing = Thing.create(:name => "Tree")
553
+ @property1 = Property.create
554
+ @property2 = Property.create
555
+ @property3 = Property.create
556
+ @thing.properties << @property1
557
+ @thing.properties << @property2
558
+ @thing.properties << @property3
559
+ end
560
+
561
+ should "should destroy the associated documents" do
562
+ @thing.properties.count.should == 3
563
+ @thing.destroy
564
+ @thing.properties.count.should == 0
565
+ Property.count.should == 0
566
+ end
567
+ end
568
+
569
+ context "=> delete_all" do
570
+ setup do
571
+ Property.key :thing_id, ObjectId
572
+ Property.belongs_to :thing
573
+ Thing.has_many :properties, :dependent => :delete_all
574
+
575
+ @thing = Thing.create(:name => "Tree")
576
+ @property1 = Property.create
577
+ @property2 = Property.create
578
+ @property3 = Property.create
579
+ @thing.properties << @property1
580
+ @thing.properties << @property2
581
+ @thing.properties << @property3
582
+ end
583
+
584
+ should "should delete associated documents" do
585
+ @thing.properties.count.should == 3
586
+ @thing.destroy
587
+ @thing.properties.count.should == 0
588
+ Property.count.should == 0
589
+ end
590
+ end
591
+
592
+ context "=> nullify" do
593
+ setup do
594
+ Property.key :thing_id, ObjectId
595
+ Property.belongs_to :thing
596
+ Thing.has_many :properties, :dependent => :nullify
597
+
598
+ @thing = Thing.create(:name => "Tree")
599
+ @property1 = Property.create
600
+ @property2 = Property.create
601
+ @property3 = Property.create
602
+ @thing.properties << @property1
603
+ @thing.properties << @property2
604
+ @thing.properties << @property3
605
+ end
606
+
607
+ should "should nullify relationship but not destroy associated documents" do
608
+ @thing.properties.count.should == 3
609
+ @thing.destroy
610
+ @thing.properties.count.should == 0
611
+ Property.count.should == 3
612
+ end
613
+ end
614
+ end
615
+ end