tpitale-mongo_mapper 0.6.9 → 0.6.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) 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 +64 -0
  7. data/lib/mongo_mapper/associations/proxy.rb +7 -4
  8. data/lib/mongo_mapper/associations.rb +11 -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_polymorphic_proxy.rb +8 -0
  25. data/test/functional/associations/test_belongs_to_proxy.rb +54 -9
  26. data/test/functional/associations/test_in_array_proxy.rb +309 -0
  27. data/test/functional/associations/test_many_documents_proxy.rb +103 -53
  28. data/test/functional/associations/test_many_embedded_proxy.rb +4 -14
  29. data/test/functional/associations/test_many_polymorphic_proxy.rb +4 -3
  30. data/test/functional/associations/test_one_proxy.rb +149 -0
  31. data/test/functional/test_binary.rb +13 -4
  32. data/test/functional/test_callbacks.rb +1 -5
  33. data/test/functional/test_dirty.rb +1 -4
  34. data/test/functional/test_document.rb +576 -640
  35. data/test/functional/test_embedded_document.rb +7 -20
  36. data/test/functional/test_modifiers.rb +238 -0
  37. data/test/functional/test_pagination.rb +1 -3
  38. data/test/functional/test_string_id_compatibility.rb +3 -8
  39. data/test/functional/test_validations.rb +13 -75
  40. data/test/models.rb +1 -1
  41. data/test/support/timing.rb +1 -1
  42. data/test/test_helper.rb +28 -0
  43. data/test/unit/associations/test_base.rb +54 -13
  44. data/test/unit/associations/test_proxy.rb +12 -0
  45. data/test/unit/test_document.rb +36 -26
  46. data/test/unit/test_embedded_document.rb +14 -51
  47. data/test/unit/test_finder_options.rb +36 -7
  48. data/test/unit/test_key.rb +1 -4
  49. data/test/unit/test_pagination.rb +6 -0
  50. data/test/unit/test_rails_compatibility.rb +4 -1
  51. data/test/unit/test_serializations.rb +1 -2
  52. data/test/unit/test_support.rb +4 -0
  53. data/test/unit/test_time_zones.rb +1 -2
  54. data/test/unit/test_validations.rb +3 -14
  55. metadata +12 -6
  56. data/lib/mongo_mapper/observing.rb +0 -50
  57. data/test/unit/test_observing.rb +0 -101
@@ -0,0 +1,309 @@
1
+ require 'test_helper'
2
+
3
+ class InArrayProxyTest < Test::Unit::TestCase
4
+ context "description" do
5
+ setup do
6
+ class ::List
7
+ include MongoMapper::Document
8
+ key :name, String, :required => true
9
+ end
10
+
11
+ class ::User
12
+ include MongoMapper::Document
13
+ key :name, String, :required => true
14
+ key :list_ids, Array
15
+ many :lists, :in => :list_ids
16
+ end
17
+ User.collection.remove
18
+ List.collection.remove
19
+ end
20
+
21
+ teardown do
22
+ Object.send :remove_const, 'List' if defined?(::List)
23
+ Object.send :remove_const, 'User' if defined?(::User)
24
+ end
25
+
26
+ should "default reader to empty array" do
27
+ User.new.lists.should == []
28
+ end
29
+
30
+ should "allow adding to association like it was an array" do
31
+ user = User.new(:name => 'John')
32
+ user.lists << List.new(:name => 'Foo1!')
33
+ user.lists.push List.new(:name => 'Foo2!')
34
+ user.lists.concat List.new(:name => 'Foo3!')
35
+ user.lists.size.should == 3
36
+ end
37
+
38
+ should "ignore adding duplicate ids" do
39
+ user = User.create(:name => 'John')
40
+ list = List.create(:name => 'Foo')
41
+ user.lists << list
42
+ user.lists << list
43
+ user.lists << list
44
+
45
+ user.list_ids.should == [list.id]
46
+ user.lists.count.should == 1
47
+ end
48
+
49
+ should "be able to replace the association" do
50
+ user = User.new(:name => 'John')
51
+ list = List.new(:name => 'Foo')
52
+ user.lists = [list]
53
+ user.save.should be_true
54
+
55
+ user.reload
56
+ user.list_ids.should == [list.id]
57
+ user.lists.size.should == 1
58
+ user.lists[0].name.should == 'Foo'
59
+ end
60
+
61
+ context "create" do
62
+ setup do
63
+ @user = User.create(:name => 'John')
64
+ @list = @user.lists.create(:name => 'Foo!')
65
+ end
66
+
67
+ should "add id to key" do
68
+ @user.list_ids.should include(@list.id)
69
+ end
70
+
71
+ should "persist id addition to key in database" do
72
+ @user.reload
73
+ @user.list_ids.should include(@list.id)
74
+ end
75
+
76
+ should "add doc to association" do
77
+ @user.lists.should include(@list)
78
+ end
79
+
80
+ should "save doc" do
81
+ @list.should_not be_new
82
+ end
83
+ end
84
+
85
+ context "create!" do
86
+ setup do
87
+ @user = User.create(:name => 'John')
88
+ @list = @user.lists.create!(:name => 'Foo!')
89
+ end
90
+
91
+ should "add id to key" do
92
+ @user.list_ids.should include(@list.id)
93
+ end
94
+
95
+ should "persist id addition to key in database" do
96
+ @user.reload
97
+ @user.list_ids.should include(@list.id)
98
+ end
99
+
100
+ should "add doc to association" do
101
+ @user.lists.should include(@list)
102
+ end
103
+
104
+ should "save doc" do
105
+ @list.should_not be_new
106
+ end
107
+
108
+ should "raise exception if invalid" do
109
+ assert_raises(MongoMapper::DocumentNotValid) do
110
+ @user.lists.create!
111
+ end
112
+ end
113
+ end
114
+
115
+ context "Finding scoped to association" do
116
+ setup do
117
+ @user = User.create(:name => 'John')
118
+ @user2 = User.create(:name => 'Brandon')
119
+ @list1 = @user.lists.create!(:name => 'Foo 1', :position => 1)
120
+ @list2 = @user.lists.create!(:name => 'Foo 2', :position => 2)
121
+ @list3 = @user2.lists.create!(:name => 'Foo 3', :position => 1)
122
+ end
123
+
124
+ context "all" do
125
+ should "work" do
126
+ @user.lists.find(:all, :order => :position.asc).should == [@list1, @list2]
127
+ @user.lists.all(:order => :position.asc).should == [@list1, @list2]
128
+ end
129
+
130
+ should "work with conditions" do
131
+ @user.lists.find(:all, :name => 'Foo 1').should == [@list1]
132
+ @user.lists.all(:name => 'Foo 1').should == [@list1]
133
+ end
134
+ end
135
+
136
+ context "first" do
137
+ should "work" do
138
+ @user.lists.find(:first, :order => 'position').should == @list1
139
+ @user.lists.first(:order => 'position').should == @list1
140
+ end
141
+
142
+ should "work with conditions" do
143
+ @user.lists.find(:first, :position => 2).should == @list2
144
+ @user.lists.first(:position => 2).should == @list2
145
+ end
146
+ end
147
+
148
+ context "last" do
149
+ should "work" do
150
+ @user.lists.find(:last, :order => 'position').should == @list2
151
+ @user.lists.last(:order => 'position').should == @list2
152
+ end
153
+
154
+ should "work with conditions" do
155
+ @user.lists.find(:last, :position => 2, :order => 'position').should == @list2
156
+ @user.lists.last(:position => 2, :order => 'position').should == @list2
157
+ end
158
+ end
159
+
160
+ context "with one id" do
161
+ should "work for id in association" do
162
+ @user.lists.find(@list1.id).should == @list1
163
+ end
164
+
165
+ should "not work for id not in association" do
166
+ @user.lists.find(@list3.id).should be_nil
167
+ end
168
+
169
+ should "raise error when using ! and not found" do
170
+ assert_raises MongoMapper::DocumentNotFound do
171
+ @user.lists.find!(@list3.id)
172
+ end
173
+ end
174
+ end
175
+
176
+ context "with multiple ids" do
177
+ should "work for ids in association" do
178
+ @user.lists.find(@list1.id, @list2.id).should == [@list1, @list2]
179
+ end
180
+
181
+ should "not work for ids not in association" do
182
+ @user.lists.find(@list1.id, @list2.id, @list3.id).should == [@list1, @list2]
183
+ end
184
+ end
185
+
186
+ context "with #paginate" do
187
+ setup do
188
+ @lists = @user.lists.paginate(:per_page => 1, :page => 1, :order => 'position')
189
+ end
190
+
191
+ should "return total pages" do
192
+ @lists.total_pages.should == 2
193
+ end
194
+
195
+ should "return total entries" do
196
+ @lists.total_entries.should == 2
197
+ end
198
+
199
+ should "return the subject" do
200
+ @lists.collect(&:name).should == ['Foo 1']
201
+ end
202
+ end
203
+
204
+ context "dynamic finders" do
205
+ should "work with single key" do
206
+ @user.lists.find_by_name('Foo 1').should == @list1
207
+ @user.lists.find_by_name!('Foo 1').should == @list1
208
+ @user.lists.find_by_name('Foo 3').should be_nil
209
+ end
210
+
211
+ should "work with multiple keys" do
212
+ @user.lists.find_by_name_and_position('Foo 1', 1).should == @list1
213
+ @user.lists.find_by_name_and_position!('Foo 1', 1).should == @list1
214
+ @user.lists.find_by_name_and_position('Foo 3', 1).should be_nil
215
+ end
216
+
217
+ should "raise error when using ! and not found" do
218
+ assert_raises(MongoMapper::DocumentNotFound) do
219
+ @user.lists.find_by_name!('Foo 3')
220
+ end
221
+ end
222
+
223
+ context "find_or_create_by" do
224
+ should "not create document if found" do
225
+ lambda {
226
+ list = @user.lists.find_or_create_by_name('Foo 1')
227
+ list.should == @list1
228
+ }.should_not change { List.count }
229
+ end
230
+
231
+ should "create document if not found" do
232
+ lambda {
233
+ list = @user.lists.find_or_create_by_name('Home')
234
+ @user.lists.should include(list)
235
+ }.should change { List.count }
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ context "count" do
242
+ setup do
243
+ @user = User.create(:name => 'John')
244
+ @user2 = User.create(:name => 'Brandon')
245
+ @list1 = @user.lists.create!(:name => 'Foo 1')
246
+ @list2 = @user.lists.create!(:name => 'Foo 2')
247
+ @list3 = @user2.lists.create!(:name => 'Foo 3')
248
+ end
249
+
250
+ should "return number of ids" do
251
+ @user.lists.count.should == 2
252
+ @user2.lists.count.should == 1
253
+ end
254
+
255
+ should "return correct count when given criteria" do
256
+ @user.lists.count(:name => 'Foo 1').should == 1
257
+ @user2.lists.count(:name => 'Foo 1').should == 0
258
+ end
259
+ end
260
+
261
+ context "Removing documents" do
262
+ setup do
263
+ @user = User.create(:name => 'John')
264
+ @user2 = User.create(:name => 'Brandon')
265
+ @list1 = @user.lists.create!(:name => 'Foo 1', :position => 1)
266
+ @list2 = @user.lists.create!(:name => 'Foo 2', :position => 2)
267
+ @list3 = @user2.lists.create!(:name => 'Foo 3', :position => 1)
268
+ end
269
+
270
+ context "destroy_all" do
271
+ should "work" do
272
+ @user.lists.count.should == 2
273
+ @user.lists.destroy_all
274
+ @user.lists.count.should == 0
275
+ end
276
+
277
+ should "work with conditions" do
278
+ @user.lists.count.should == 2
279
+ @user.lists.destroy_all(:name => 'Foo 1')
280
+ @user.lists.count.should == 1
281
+ end
282
+ end
283
+
284
+ context "delete_all" do
285
+ should "work" do
286
+ @user.lists.count.should == 2
287
+ @user.lists.delete_all
288
+ @user.lists.count.should == 0
289
+ end
290
+
291
+ should "work with conditions" do
292
+ @user.lists.count.should == 2
293
+ @user.lists.delete_all(:name => 'Foo 1')
294
+ @user.lists.count.should == 1
295
+ end
296
+ end
297
+
298
+ should "work with nullify" do
299
+ @user.lists.count.should == 2
300
+
301
+ lambda {
302
+ @user.lists.nullify
303
+ }.should_not change { List.count }
304
+
305
+ @user.lists.count.should == 0
306
+ end
307
+ end
308
+ end
309
+ end
@@ -22,10 +22,10 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
22
22
 
23
23
  should "be able to replace the association" do
24
24
  project = Project.new
25
- project.statuses = [Status.new("name" => "ready")]
25
+ project.statuses = [Status.new(:name => "ready")]
26
26
  project.save.should be_true
27
27
 
28
- project = project.reload
28
+ project.reload
29
29
  project.statuses.size.should == 1
30
30
  project.statuses[0].name.should == "ready"
31
31
  end
@@ -36,7 +36,7 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
36
36
  project.statuses.push Status.new(:name => 'push')
37
37
  project.statuses.concat Status.new(:name => 'concat')
38
38
 
39
- project = project.reload
39
+ project.reload
40
40
  project.statuses[0].project_id.should == project.id
41
41
  project.statuses[1].project_id.should == project.id
42
42
  project.statuses[2].project_id.should == project.id
@@ -235,84 +235,44 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
235
235
  lambda {
236
236
  status = @project1.statuses.find_or_create_by_name('Delivered')
237
237
  status.project.should == @project1
238
- }.should change { Status.count }.by(1)
238
+ }.should change { Status.count }
239
239
  end
240
240
  end
241
241
  end
242
242
 
243
- context "with :all" do
243
+ context "all" do
244
244
  should "work" do
245
245
  @project1.statuses.find(:all, :order => "position asc").should == [@brand_new, @complete]
246
- end
247
-
248
- should "work with conditions" do
249
- statuses = @project1.statuses.find(:all, :name => 'Complete')
250
- statuses.should == [@complete]
251
- end
252
-
253
- should "work with order" do
254
- statuses = @project1.statuses.find(:all, :order => 'name asc')
255
- statuses.should == [@complete, @brand_new]
256
- end
257
- end
258
-
259
- context "with #all" do
260
- should "work" do
261
246
  @project1.statuses.all(:order => "position asc").should == [@brand_new, @complete]
262
247
  end
263
248
 
264
249
  should "work with conditions" do
265
- statuses = @project1.statuses.all(:name => 'Complete')
266
- statuses.should == [@complete]
267
- end
268
-
269
- should "work with order" do
270
- statuses = @project1.statuses.all(:order => 'name asc')
271
- statuses.should == [@complete, @brand_new]
250
+ @project1.statuses.find(:all, :name => 'Complete').should == [@complete]
251
+ @project1.statuses.all(:name => 'Complete').should == [@complete]
272
252
  end
273
253
  end
274
254
 
275
- context "with :first" do
255
+ context "first" do
276
256
  should "work" do
277
257
  @project1.statuses.find(:first, :order => 'name').should == @complete
278
- end
279
-
280
- should "work with conditions" do
281
- status = @project1.statuses.find(:first, :name => 'Complete')
282
- status.should == @complete
283
- end
284
- end
285
-
286
- context "with #first" do
287
- should "work" do
288
258
  @project1.statuses.first(:order => 'name').should == @complete
289
259
  end
290
260
 
291
261
  should "work with conditions" do
292
- status = @project1.statuses.first(:name => 'Complete')
293
- status.should == @complete
262
+ @project1.statuses.find(:first, :name => 'Complete').should == @complete
263
+ @project1.statuses.first(:name => 'Complete').should == @complete
294
264
  end
295
265
  end
296
266
 
297
- context "with :last" do
267
+ context "last" do
298
268
  should "work" do
299
269
  @project1.statuses.find(:last, :order => "position asc").should == @complete
300
- end
301
-
302
- should "work with conditions" do
303
- status = @project1.statuses.find(:last, :order => 'position', :name => 'New')
304
- status.should == @brand_new
305
- end
306
- end
307
-
308
- context "with #last" do
309
- should "work" do
310
270
  @project1.statuses.last(:order => "position asc").should == @complete
311
271
  end
312
272
 
313
273
  should "work with conditions" do
314
- status = @project1.statuses.last(:order => 'position', :name => 'New')
315
- status.should == @brand_new
274
+ @project1.statuses.find(:last, :order => 'position', :name => 'New').should == @brand_new
275
+ @project1.statuses.last(:order => 'position', :name => 'New').should == @brand_new
316
276
  end
317
277
  end
318
278
 
@@ -384,4 +344,94 @@ class ManyDocumentsProxyTest < Test::Unit::TestCase
384
344
  project.collaborators.top.should == collaborator1
385
345
  end
386
346
  end
347
+
348
+ context ":dependent" do
349
+ setup do
350
+ # FIXME: make use of already defined models
351
+ class ::Property
352
+ include MongoMapper::Document
353
+ end
354
+ Property.collection.remove
355
+
356
+ class ::Thing
357
+ include MongoMapper::Document
358
+ key :name, String
359
+ end
360
+ Thing.collection.remove
361
+ end
362
+
363
+ teardown do
364
+ Object.send :remove_const, 'Property' if defined?(::Property)
365
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
366
+ end
367
+
368
+ context "=> destroy" do
369
+ setup do
370
+ Property.key :thing_id, ObjectId
371
+ Property.belongs_to :thing, :dependent => :destroy
372
+ Thing.many :properties, :dependent => :destroy
373
+
374
+ @thing = Thing.create(:name => "Tree")
375
+ @property1 = Property.create
376
+ @property2 = Property.create
377
+ @property3 = Property.create
378
+ @thing.properties << @property1
379
+ @thing.properties << @property2
380
+ @thing.properties << @property3
381
+ end
382
+
383
+ should "should destroy the associated documents" do
384
+ @thing.properties.count.should == 3
385
+ @thing.destroy
386
+ @thing.properties.count.should == 0
387
+ Property.count.should == 0
388
+ end
389
+ end
390
+
391
+ context "=> delete_all" do
392
+ setup do
393
+ Property.key :thing_id, ObjectId
394
+ Property.belongs_to :thing
395
+ Thing.has_many :properties, :dependent => :delete_all
396
+
397
+ @thing = Thing.create(:name => "Tree")
398
+ @property1 = Property.create
399
+ @property2 = Property.create
400
+ @property3 = Property.create
401
+ @thing.properties << @property1
402
+ @thing.properties << @property2
403
+ @thing.properties << @property3
404
+ end
405
+
406
+ should "should delete associated documents" do
407
+ @thing.properties.count.should == 3
408
+ @thing.destroy
409
+ @thing.properties.count.should == 0
410
+ Property.count.should == 0
411
+ end
412
+ end
413
+
414
+ context "=> nullify" do
415
+ setup do
416
+ Property.key :thing_id, ObjectId
417
+ Property.belongs_to :thing
418
+ Thing.has_many :properties, :dependent => :nullify
419
+
420
+ @thing = Thing.create(:name => "Tree")
421
+ @property1 = Property.create
422
+ @property2 = Property.create
423
+ @property3 = Property.create
424
+ @thing.properties << @property1
425
+ @thing.properties << @property2
426
+ @thing.properties << @property3
427
+ end
428
+
429
+ should "should nullify relationship but not destroy associated documents" do
430
+ @thing.properties.count.should == 3
431
+ @thing.destroy
432
+ @thing.properties.count.should == 0
433
+ Property.count.should == 3
434
+ end
435
+ end
436
+ end
387
437
  end
@@ -33,12 +33,9 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
33
33
  end
34
34
 
35
35
  should "allow embedding arbitrarily deep" do
36
- @document = Class.new do
37
- include MongoMapper::Document
38
- set_collection_name 'test'
36
+ @document = Doc do
39
37
  key :person, Person
40
38
  end
41
- @document.collection.remove
42
39
 
43
40
  meg = Person.new(:name => "Meg")
44
41
  meg.child = Person.new(:name => "Steve")
@@ -80,12 +77,9 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
80
77
 
81
78
  context "embedding many embedded documents" do
82
79
  setup do
83
- @document = Class.new do
84
- include MongoMapper::Document
85
- set_collection_name 'test'
80
+ @document = Doc do
86
81
  many :people
87
82
  end
88
- @document.collection.remove
89
83
  end
90
84
 
91
85
  should "persist all embedded documents" do
@@ -142,20 +136,16 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
142
136
 
143
137
  context "extending the association" do
144
138
  setup do
145
- @address_class = Class.new do
146
- include MongoMapper::EmbeddedDocument
139
+ @address_class = EDoc do
147
140
  key :address, String
148
141
  key :city, String
149
142
  key :state, String
150
143
  key :zip, Integer
151
144
  end
152
145
 
153
- @project_class = Class.new do
154
- include MongoMapper::Document
146
+ @project_class = Doc do
155
147
  key :name, String
156
148
  end
157
-
158
- @project_class.collection.remove
159
149
  end
160
150
 
161
151
  should "work using a block passed to many" do
@@ -134,8 +134,8 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
134
134
 
135
135
  @hall = Room.create(:name => 'Hall')
136
136
  @hm1 = Message.create(:body => 'Do not fall in the hall', :position => 1)
137
- @hm2 = Message.create(:body => 'Hall the king!', :position => 2)
138
137
  @hm3 = Message.create(:body => 'Loungin!', :position => 3)
138
+ @hm2 = Message.create(:body => 'Hall the king!', :position => 2)
139
139
  @hall.messages = [@hm1, @hm2, @hm3]
140
140
  @hall.save
141
141
  end
@@ -270,7 +270,7 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
270
270
  end
271
271
 
272
272
  should "allow overriding the order provided to the association" do
273
- @lounge.messages.all(:order => 'position desc').should == [@lm2, @lm1]
273
+ @lounge.messages.all(:order => 'position').should == [@lm1, @lm2]
274
274
  end
275
275
 
276
276
  should "allow using conditions on association" do
@@ -326,10 +326,11 @@ class ManyPolymorphicProxyTest < Test::Unit::TestCase
326
326
  end
327
327
 
328
328
  should "work using many's :extend option" do
329
+
329
330
  room = Room.new(:name => "Amazing Room")
330
331
  accounts = room.accounts = [
331
332
  Bot.new(:last_logged_in => 3.weeks.ago),
332
- User.new(:last_logged_in => nil),
333
+ AccountUser.new(:last_logged_in => nil),
333
334
  Bot.new(:last_logged_in => 1.week.ago)
334
335
  ]
335
336
  room.save