tpitale-mongo_mapper 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 (75) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +53 -0
  4. data/Rakefile +55 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/lib/mongo_mapper/associations/base.rb +110 -0
  8. data/lib/mongo_mapper/associations/belongs_to_polymorphic_proxy.rb +26 -0
  9. data/lib/mongo_mapper/associations/belongs_to_proxy.rb +21 -0
  10. data/lib/mongo_mapper/associations/collection.rb +19 -0
  11. data/lib/mongo_mapper/associations/many_documents_as_proxy.rb +26 -0
  12. data/lib/mongo_mapper/associations/many_documents_proxy.rb +115 -0
  13. data/lib/mongo_mapper/associations/many_embedded_polymorphic_proxy.rb +31 -0
  14. data/lib/mongo_mapper/associations/many_embedded_proxy.rb +54 -0
  15. data/lib/mongo_mapper/associations/many_polymorphic_proxy.rb +11 -0
  16. data/lib/mongo_mapper/associations/proxy.rb +113 -0
  17. data/lib/mongo_mapper/associations.rb +70 -0
  18. data/lib/mongo_mapper/callbacks.rb +109 -0
  19. data/lib/mongo_mapper/dirty.rb +136 -0
  20. data/lib/mongo_mapper/document.rb +472 -0
  21. data/lib/mongo_mapper/dynamic_finder.rb +74 -0
  22. data/lib/mongo_mapper/embedded_document.rb +384 -0
  23. data/lib/mongo_mapper/finder_options.rb +133 -0
  24. data/lib/mongo_mapper/key.rb +36 -0
  25. data/lib/mongo_mapper/observing.rb +50 -0
  26. data/lib/mongo_mapper/pagination.rb +55 -0
  27. data/lib/mongo_mapper/rails_compatibility/document.rb +15 -0
  28. data/lib/mongo_mapper/rails_compatibility/embedded_document.rb +27 -0
  29. data/lib/mongo_mapper/serialization.rb +54 -0
  30. data/lib/mongo_mapper/serializers/json_serializer.rb +92 -0
  31. data/lib/mongo_mapper/support.rb +206 -0
  32. data/lib/mongo_mapper/validations.rb +41 -0
  33. data/lib/mongo_mapper.rb +120 -0
  34. data/mongo_mapper.gemspec +173 -0
  35. data/specs.watchr +32 -0
  36. data/test/NOTE_ON_TESTING +1 -0
  37. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +55 -0
  38. data/test/functional/associations/test_belongs_to_proxy.rb +48 -0
  39. data/test/functional/associations/test_many_documents_as_proxy.rb +246 -0
  40. data/test/functional/associations/test_many_documents_proxy.rb +387 -0
  41. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +156 -0
  42. data/test/functional/associations/test_many_embedded_proxy.rb +192 -0
  43. data/test/functional/associations/test_many_polymorphic_proxy.rb +339 -0
  44. data/test/functional/test_associations.rb +44 -0
  45. data/test/functional/test_binary.rb +18 -0
  46. data/test/functional/test_callbacks.rb +85 -0
  47. data/test/functional/test_dirty.rb +159 -0
  48. data/test/functional/test_document.rb +1235 -0
  49. data/test/functional/test_embedded_document.rb +135 -0
  50. data/test/functional/test_logger.rb +20 -0
  51. data/test/functional/test_pagination.rb +95 -0
  52. data/test/functional/test_rails_compatibility.rb +25 -0
  53. data/test/functional/test_string_id_compatibility.rb +72 -0
  54. data/test/functional/test_validations.rb +378 -0
  55. data/test/models.rb +271 -0
  56. data/test/support/custom_matchers.rb +55 -0
  57. data/test/support/timing.rb +16 -0
  58. data/test/test_helper.rb +27 -0
  59. data/test/unit/associations/test_base.rb +166 -0
  60. data/test/unit/associations/test_proxy.rb +91 -0
  61. data/test/unit/serializers/test_json_serializer.rb +189 -0
  62. data/test/unit/test_document.rb +204 -0
  63. data/test/unit/test_dynamic_finder.rb +125 -0
  64. data/test/unit/test_embedded_document.rb +718 -0
  65. data/test/unit/test_finder_options.rb +296 -0
  66. data/test/unit/test_key.rb +172 -0
  67. data/test/unit/test_mongo_mapper.rb +65 -0
  68. data/test/unit/test_observing.rb +101 -0
  69. data/test/unit/test_pagination.rb +113 -0
  70. data/test/unit/test_rails_compatibility.rb +49 -0
  71. data/test/unit/test_serializations.rb +52 -0
  72. data/test/unit/test_support.rb +342 -0
  73. data/test/unit/test_time_zones.rb +40 -0
  74. data/test/unit/test_validations.rb +503 -0
  75. metadata +235 -0
@@ -0,0 +1,192 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyEmbeddedProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Project.collection.remove
7
+ RealPerson.collection.remove
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ Project.new.addresses.should == []
12
+ end
13
+
14
+ should "allow adding to association like it was an array" do
15
+ project = Project.new
16
+ project.addresses << Address.new
17
+ project.addresses.push Address.new
18
+ project.addresses.size.should == 2
19
+ end
20
+
21
+ should "be embedded in document on save" do
22
+ sb = Address.new(:city => 'South Bend', :state => 'IN')
23
+ chi = Address.new(:city => 'Chicago', :state => 'IL')
24
+ project = Project.new
25
+ project.addresses << sb
26
+ project.addresses << chi
27
+ project.save
28
+
29
+ project.reload
30
+ project.addresses.size.should == 2
31
+ project.addresses[0].should == sb
32
+ project.addresses[1].should == chi
33
+ end
34
+
35
+ should "allow embedding arbitrarily deep" do
36
+ @document = Class.new do
37
+ include MongoMapper::Document
38
+ set_collection_name 'test'
39
+ key :person, Person
40
+ end
41
+ @document.collection.remove
42
+
43
+ meg = Person.new(:name => "Meg")
44
+ meg.child = Person.new(:name => "Steve")
45
+ meg.child.child = Person.new(:name => "Linda")
46
+
47
+ doc = @document.new(:person => meg)
48
+ doc.save
49
+
50
+ doc.reload
51
+ doc.person.name.should == 'Meg'
52
+ doc.person.child.name.should == 'Steve'
53
+ doc.person.child.child.name.should == 'Linda'
54
+ end
55
+
56
+ should "allow assignment of 'many' embedded documents using a hash" do
57
+ person_attributes = {
58
+ "name" => "Mr. Pet Lover",
59
+ "pets" => [
60
+ {"name" => "Jimmy", "species" => "Cocker Spainel"},
61
+ {"name" => "Sasha", "species" => "Siberian Husky"},
62
+ ]
63
+ }
64
+
65
+ pet_lover = RealPerson.new(person_attributes)
66
+ pet_lover.name.should == "Mr. Pet Lover"
67
+ pet_lover.pets[0].name.should == "Jimmy"
68
+ pet_lover.pets[0].species.should == "Cocker Spainel"
69
+ pet_lover.pets[1].name.should == "Sasha"
70
+ pet_lover.pets[1].species.should == "Siberian Husky"
71
+ pet_lover.save.should be_true
72
+
73
+ pet_lover.reload
74
+ pet_lover.name.should == "Mr. Pet Lover"
75
+ pet_lover.pets[0].name.should == "Jimmy"
76
+ pet_lover.pets[0].species.should == "Cocker Spainel"
77
+ pet_lover.pets[1].name.should == "Sasha"
78
+ pet_lover.pets[1].species.should == "Siberian Husky"
79
+ end
80
+
81
+ context "embedding many embedded documents" do
82
+ setup do
83
+ @document = Class.new do
84
+ include MongoMapper::Document
85
+ set_collection_name 'test'
86
+ many :people
87
+ end
88
+ @document.collection.remove
89
+ end
90
+
91
+ should "persist all embedded documents" do
92
+ meg = Person.new(:name => "Meg")
93
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
94
+ koda = Pet.new(:name => "Koda", :species => "Dog")
95
+
96
+ doc = @document.new
97
+ meg.pets << sparky
98
+ meg.pets << koda
99
+ doc.people << meg
100
+ doc.save
101
+
102
+ doc.reload
103
+ doc.people.first.name.should == "Meg"
104
+ doc.people.first.pets.should_not == []
105
+ doc.people.first.pets.first.name.should == "Sparky"
106
+ doc.people.first.pets.first.species.should == "Dog"
107
+ doc.people.first.pets[1].name.should == "Koda"
108
+ doc.people.first.pets[1].species.should == "Dog"
109
+ end
110
+
111
+ should "create a reference to the root document for all embedded documents before save" do
112
+ meg = Person.new(:name => "Meg")
113
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
114
+ doc = @document.new
115
+ doc.people << meg
116
+ meg.pets << sparky
117
+
118
+ doc.people.first._root_document.should == doc
119
+ doc.people.first.pets.first._root_document.should == doc
120
+ end
121
+
122
+ should "create a reference to the root document for all embedded documents" do
123
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
124
+ meg = Person.new(:name => "Meg", :pets => [sparky])
125
+ doc = @document.new
126
+ doc.people << meg
127
+ doc.save
128
+
129
+ doc.reload
130
+ doc.people.first._root_document.should == doc
131
+ doc.people.first.pets.first._root_document.should == doc
132
+ end
133
+ end
134
+
135
+ should "allow finding by id" do
136
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
137
+ meg = Person.new(:name => "Meg", :pets => [sparky])
138
+
139
+ meg.pets.find(sparky._id).should == sparky # oid
140
+ meg.pets.find(sparky.id.to_s).should == sparky # string
141
+ end
142
+
143
+ context "extending the association" do
144
+ setup do
145
+ @address_class = Class.new do
146
+ include MongoMapper::EmbeddedDocument
147
+ key :address, String
148
+ key :city, String
149
+ key :state, String
150
+ key :zip, Integer
151
+ end
152
+
153
+ @project_class = Class.new do
154
+ include MongoMapper::Document
155
+ key :name, String
156
+ end
157
+
158
+ @project_class.collection.remove
159
+ end
160
+
161
+ should "work using a block passed to many" do
162
+ @project_class.many :addresses, :class => @address_class do
163
+ def find_all_by_state(state)
164
+ find_all { |a| a.state == state }
165
+ end
166
+ end
167
+
168
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
169
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
170
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
171
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
172
+
173
+ project.addresses.find_all_by_state("CA").should == [addr1, addr2]
174
+ end
175
+
176
+ should "work using many's :extend option" do
177
+ module FindByCity
178
+ def find_by_city(city)
179
+ find_all { |a| a.city == city }
180
+ end
181
+ end
182
+ @project_class.many :addresses, :class => @address_class, :extend => FindByCity
183
+
184
+ addr1 = @address_class.new(:address => "Gate-3 Lankershim Blvd.", :city => "Universal City", :state => "CA", :zip => "91608")
185
+ addr2 = @address_class.new(:address => "3000 W. Alameda Ave.", :city => "Burbank", :state => "CA", :zip => "91523")
186
+ addr3 = @address_class.new(:address => "111 Some Ln", :city => "Nashville", :state => "TN", :zip => "37211")
187
+ project = @project_class.create(:name => "Some Project", :addresses => [addr1, addr2, addr3])
188
+
189
+ project.addresses.find_by_city('Burbank').should == [addr2]
190
+ end
191
+ end
192
+ end
@@ -0,0 +1,339 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ Room.collection.remove
7
+ Message.collection.remove
8
+ end
9
+
10
+ should "default reader to empty array" do
11
+ Room.new.messages.should == []
12
+ end
13
+
14
+ should "add type key to polymorphic class base" do
15
+ Message.keys.keys.should include('_type')
16
+ end
17
+
18
+ should "allow adding to assiciation like it was an array" do
19
+ room = Room.new
20
+ room.messages << Enter.new
21
+ room.messages.push Exit.new
22
+ room.messages.concat Exit.new
23
+ room.messages.size.should == 3
24
+ end
25
+
26
+ should "be able to replace the association" do
27
+ room = Room.create(:name => 'Lounge')
28
+
29
+ lambda {
30
+ room.messages = [
31
+ Enter.new(:body => 'John entered room', :position => 1),
32
+ Chat.new(:body => 'Heyyyoooo!', :position => 2),
33
+ Exit.new(:body => 'John exited room', :position => 3)
34
+ ]
35
+ }.should change { Message.count }.by(3)
36
+
37
+ room = room.reload
38
+ messages = room.messages.all :order => "position"
39
+ messages.size.should == 3
40
+ messages[0].body.should == 'John entered room'
41
+ messages[1].body.should == 'Heyyyoooo!'
42
+ messages[2].body.should == 'John exited room'
43
+ end
44
+
45
+ should "correctly store type when using <<, push and concat" do
46
+ room = Room.new
47
+ room.messages << Enter.new(:body => 'John entered the room', :position => 1)
48
+ room.messages.push Exit.new(:body => 'John entered the room', :position => 2)
49
+ room.messages.concat Chat.new(:body => 'Holla!' , :position => 3)
50
+
51
+ room = room.reload
52
+ messages = room.messages.all :order => "position"
53
+ messages[0]._type.should == 'Enter'
54
+ messages[1]._type.should == 'Exit'
55
+ messages[2]._type.should == 'Chat'
56
+ end
57
+
58
+ context "build" do
59
+ should "assign foreign key" do
60
+ room = Room.create
61
+ message = room.messages.build
62
+ message.room_id.should == room._id
63
+ end
64
+
65
+ should "assign _type" do
66
+ room = Room.create
67
+ message = room.messages.build
68
+ message._type.should == 'Message'
69
+ end
70
+
71
+ should "allow assigning attributes" do
72
+ room = Room.create
73
+ message = room.messages.build(:body => 'Foo!')
74
+ message.body.should == 'Foo!'
75
+ end
76
+ end
77
+
78
+ context "create" do
79
+ should "assign foreign key" do
80
+ room = Room.create
81
+ message = room.messages.create
82
+ message.room_id.should == room._id
83
+ end
84
+
85
+ should "assign _type" do
86
+ room = Room.create
87
+ message = room.messages.create
88
+ message._type.should == 'Message'
89
+ end
90
+
91
+ should "save record" do
92
+ room = Room.create
93
+ lambda {
94
+ room.messages.create
95
+ }.should change { Message.count }
96
+ end
97
+
98
+ should "allow passing attributes" do
99
+ room = Room.create
100
+ message = room.messages.create(:body => 'Foo!')
101
+ message.body.should == 'Foo!'
102
+ end
103
+ end
104
+
105
+ context "count" do
106
+ should "work scoped to association" do
107
+ room = Room.create
108
+ 3.times { room.messages.create }
109
+
110
+ other_room = Room.create
111
+ 2.times { other_room.messages.create }
112
+
113
+ room.messages.count.should == 3
114
+ other_room.messages.count.should == 2
115
+ end
116
+
117
+ should "work with conditions" do
118
+ room = Room.create
119
+ room.messages.create(:body => 'Foo')
120
+ room.messages.create(:body => 'Other 1')
121
+ room.messages.create(:body => 'Other 2')
122
+
123
+ room.messages.count(:body => 'Foo').should == 1
124
+ end
125
+ end
126
+
127
+ context "Finding scoped to association" do
128
+ setup do
129
+ @lounge = Room.create(:name => 'Lounge')
130
+ @lm1 = Message.create(:body => 'Loungin!', :position => 1)
131
+ @lm2 = Message.create(:body => 'I love loungin!', :position => 2)
132
+ @lounge.messages = [@lm1, @lm2]
133
+ @lounge.save
134
+
135
+ @hall = Room.create(:name => 'Hall')
136
+ @hm1 = Message.create(:body => 'Do not fall in the hall', :position => 1)
137
+ @hm2 = Message.create(:body => 'Hall the king!', :position => 2)
138
+ @hm3 = Message.create(:body => 'Loungin!', :position => 3)
139
+ @hall.messages = [@hm1, @hm2, @hm3]
140
+ @hall.save
141
+ end
142
+
143
+ context "dynamic finders" do
144
+ should "work with single key" do
145
+ @lounge.messages.find_by_position(1).should == @lm1
146
+ @hall.messages.find_by_position(2).should == @hm2
147
+ end
148
+
149
+ should "work with multiple keys" do
150
+ @lounge.messages.find_by_body_and_position('Loungin!', 1).should == @lm1
151
+ @lounge.messages.find_by_body_and_position('Loungin!', 2).should be_nil
152
+ end
153
+
154
+ should "raise error when using !" do
155
+ lambda {
156
+ @lounge.messages.find_by_position!(222)
157
+ }.should raise_error(MongoMapper::DocumentNotFound)
158
+ end
159
+
160
+ context "find_or_create_by" do
161
+ should "not create document if found" do
162
+ lambda {
163
+ message = @lounge.messages.find_or_create_by_body('Loungin!')
164
+ message.room.should == @lounge
165
+ message.should == @lm1
166
+ }.should_not change { Message.count }
167
+ end
168
+
169
+ should "create document if not found" do
170
+ lambda {
171
+ message = @lounge.messages.find_or_create_by_body('Yo dawg!')
172
+ message.room.should == @lounge
173
+ message._type.should == 'Message'
174
+ }.should change { Message.count }.by(1)
175
+ end
176
+ end
177
+ end
178
+
179
+ context "with :all" do
180
+ should "work" do
181
+ @lounge.messages.find(:all, :order => "position").should == [@lm1, @lm2]
182
+ end
183
+
184
+ should "work with conditions" do
185
+ messages = @lounge.messages.find(:all, :body => 'Loungin!', :order => "position")
186
+ messages.should == [@lm1]
187
+ end
188
+
189
+ should "work with order" do
190
+ messages = @lounge.messages.find(:all, :order => 'position desc')
191
+ messages.should == [@lm2, @lm1]
192
+ end
193
+ end
194
+
195
+ context "with #all" do
196
+ should "work" do
197
+ @lounge.messages.all(:order => "position").should == [@lm1, @lm2]
198
+ end
199
+
200
+ should "work with conditions" do
201
+ messages = @lounge.messages.all(:body => 'Loungin!', :order => "position")
202
+ messages.should == [@lm1]
203
+ end
204
+
205
+ should "work with order" do
206
+ messages = @lounge.messages.all(:order => 'position desc')
207
+ messages.should == [@lm2, @lm1]
208
+ end
209
+ end
210
+
211
+ context "with :first" do
212
+ should "work" do
213
+ @lounge.messages.find(:first, :order => "position asc").should == @lm1
214
+ end
215
+
216
+ should "work with conditions" do
217
+ message = @lounge.messages.find(:first, :body => 'I love loungin!', :order => "position asc")
218
+ message.should == @lm2
219
+ end
220
+ end
221
+
222
+ context "with #first" do
223
+ should "work" do
224
+ @lounge.messages.first(:order => "position asc").should == @lm1
225
+ end
226
+
227
+ should "work with conditions" do
228
+ message = @lounge.messages.first(:body => 'I love loungin!', :order => "position asc")
229
+ message.should == @lm2
230
+ end
231
+ end
232
+
233
+ context "with :last" do
234
+ should "work" do
235
+ @lounge.messages.find(:last, :order => "position asc").should == @lm2
236
+ end
237
+
238
+ should "work with conditions" do
239
+ message = @lounge.messages.find(:last, :body => 'Loungin!', :order => "position asc")
240
+ message.should == @lm1
241
+ end
242
+ end
243
+
244
+ context "with #last" do
245
+ should "work" do
246
+ @lounge.messages.last(:order => "position asc").should == @lm2
247
+ end
248
+
249
+ should "work with conditions" do
250
+ message = @lounge.messages.last(:body => 'Loungin!', :order => "position asc")
251
+ message.should == @lm1
252
+ end
253
+ end
254
+
255
+ context "with one id" do
256
+ should "work for id in association" do
257
+ @lounge.messages.find(@lm2._id).should == @lm2
258
+ end
259
+
260
+ should "not work for id not in association" do
261
+ lambda {
262
+ @lounge.messages.find!(@hm2._id)
263
+ }.should raise_error(MongoMapper::DocumentNotFound)
264
+ end
265
+ end
266
+
267
+ context "with query options/criteria" do
268
+ should "work with order on association" do
269
+ @lounge.messages.should == [@lm1, @lm2]
270
+ end
271
+
272
+ should "allow overriding the order provided to the association" do
273
+ @lounge.messages.all(:order => 'position desc').should == [@lm2, @lm1]
274
+ end
275
+
276
+ should "allow using conditions on association" do
277
+ @hall.latest_messages.should == [@hm3, @hm2]
278
+ end
279
+ end
280
+
281
+ context "with multiple ids" do
282
+ should "work for ids in association" do
283
+ messages = @lounge.messages.find(@lm1._id, @lm2._id)
284
+ messages.should == [@lm1, @lm2]
285
+ end
286
+
287
+ should "not work for ids not in association" do
288
+ lambda {
289
+ @lounge.messages.find!(@lm1._id, @lm2._id, @hm2._id)
290
+ }.should raise_error(MongoMapper::DocumentNotFound)
291
+ end
292
+ end
293
+
294
+ context "with #paginate" do
295
+ setup do
296
+ @messages = @hall.messages.paginate(:per_page => 2, :page => 1, :order => 'position asc')
297
+ end
298
+
299
+ should "return total pages" do
300
+ @messages.total_pages.should == 2
301
+ end
302
+
303
+ should "return total entries" do
304
+ @messages.total_entries.should == 3
305
+ end
306
+
307
+ should "return the subject" do
308
+ @messages.should == [@hm1, @hm2]
309
+ end
310
+ end
311
+ end
312
+
313
+ context "extending the association" do
314
+ should "work using a block passed to many" do
315
+ room = Room.new(:name => "Amazing Room")
316
+ messages = room.messages = [
317
+ Enter.new(:body => 'John entered room', :position => 3),
318
+ Chat.new(:body => 'Heyyyoooo!', :position => 4),
319
+ Exit.new(:body => 'John exited room', :position => 5),
320
+ Enter.new(:body => 'Steve entered room', :position => 6),
321
+ Chat.new(:body => 'Anyone there?', :position => 7),
322
+ Exit.new(:body => 'Steve exited room', :position => 8)
323
+ ]
324
+ room.save
325
+ room.messages.older.should == messages[3..5]
326
+ end
327
+
328
+ should "work using many's :extend option" do
329
+ room = Room.new(:name => "Amazing Room")
330
+ accounts = room.accounts = [
331
+ Bot.new(:last_logged_in => 3.weeks.ago),
332
+ User.new(:last_logged_in => nil),
333
+ Bot.new(:last_logged_in => 1.week.ago)
334
+ ]
335
+ room.save
336
+ room.accounts.inactive.should == [accounts[1]]
337
+ end
338
+ end
339
+ end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class AssociationsTest < Test::Unit::TestCase
5
+ should "allow changing class names" do
6
+ class AwesomeUser
7
+ include MongoMapper::Document
8
+
9
+ many :posts, :class_name => 'AssociationsTest::AwesomePost', :foreign_key => :creator_id
10
+ end
11
+ AwesomeUser.collection.remove
12
+
13
+ class AwesomeTag
14
+ include MongoMapper::EmbeddedDocument
15
+
16
+ key :name, String
17
+ key :post_id, ObjectId
18
+
19
+ belongs_to :post, :class_name => 'AssociationsTest::AwesomeUser'
20
+ end
21
+
22
+ class AwesomePost
23
+ include MongoMapper::Document
24
+
25
+ key :creator_id, ObjectId
26
+
27
+ belongs_to :creator, :class_name => 'AssociationsTest::AwesomeUser'
28
+ many :tags, :class_name => 'AssociationsTest::AwesomeTag', :foreign_key => :post_id
29
+ end
30
+
31
+ AwesomeUser.collection.remove
32
+ AwesomePost.collection.remove
33
+
34
+ user = AwesomeUser.create
35
+ tag1 = AwesomeTag.new(:name => 'awesome')
36
+ tag2 = AwesomeTag.new(:name => 'grand')
37
+ post1 = AwesomePost.create(:creator => user, :tags => [tag1])
38
+ post2 = AwesomePost.create(:creator => user, :tags => [tag2])
39
+ user.posts.should == [post1, post2]
40
+
41
+ post1 = post1.reload
42
+ post1.tags.should == [tag1]
43
+ end
44
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class BinaryTest < Test::Unit::TestCase
4
+ should "serialize and deserialize correctly" do
5
+ klass = Class.new do
6
+ include MongoMapper::Document
7
+ set_collection_name 'test'
8
+ key :contents, Binary
9
+ end
10
+ klass.collection.remove
11
+
12
+ doc = klass.new(:contents => '010101')
13
+ doc.save
14
+
15
+ doc = doc.reload
16
+ doc.contents.to_s.should == ByteBuffer.new('010101').to_s
17
+ end
18
+ end
@@ -0,0 +1,85 @@
1
+ require 'test_helper'
2
+
3
+ class CallbacksTest < Test::Unit::TestCase
4
+ context "Defining and running callbacks" do
5
+ setup do
6
+ @document = Class.new do
7
+ include MongoMapper::Document
8
+ set_collection_name 'test'
9
+
10
+ key :name, String
11
+
12
+ [ :before_validation_on_create, :before_validation_on_update,
13
+ :before_validation, :after_validation,
14
+ :before_create, :after_create,
15
+ :before_update, :after_update,
16
+ :before_save, :after_save,
17
+ :before_destroy, :after_destroy].each do |callback|
18
+ callback_method = "#{callback}_callback"
19
+ send(callback, callback_method)
20
+ define_method(callback_method) do
21
+ history << callback.to_sym
22
+ end
23
+ end
24
+
25
+ def history
26
+ @history ||= []
27
+ end
28
+
29
+ def clear_history
30
+ @history = nil
31
+ end
32
+ end
33
+ @document.collection.remove
34
+ end
35
+
36
+ should "get the order right for creating documents" do
37
+ doc = @document.create(:name => 'John Nunemaker')
38
+ doc.history.should == [:before_validation, :before_validation_on_create, :after_validation, :before_save, :before_create, :after_create, :after_save]
39
+ end
40
+
41
+ should "get the order right for updating documents" do
42
+ doc = @document.create(:name => 'John Nunemaker')
43
+ doc.clear_history
44
+ doc.name = 'John'
45
+ doc.save
46
+ doc.history.should == [:before_validation, :before_validation_on_update, :after_validation, :before_save, :before_update, :after_update, :after_save]
47
+ end
48
+
49
+ should "work for before and after validation" do
50
+ doc = @document.new(:name => 'John Nunemaker')
51
+ doc.valid?
52
+ doc.history.should include(:before_validation)
53
+ doc.history.should include(:after_validation)
54
+ end
55
+
56
+ should "work for before and after create" do
57
+ doc = @document.create(:name => 'John Nunemaker')
58
+ doc.history.should include(:before_create)
59
+ doc.history.should include(:after_create)
60
+ end
61
+
62
+ should "work for before and after update" do
63
+ doc = @document.create(:name => 'John Nunemaker')
64
+ doc.name = 'John Doe'
65
+ doc.save
66
+ doc.history.should include(:before_update)
67
+ doc.history.should include(:after_update)
68
+ end
69
+
70
+ should "work for before and after save" do
71
+ doc = @document.new
72
+ doc.name = 'John Doe'
73
+ doc.save
74
+ doc.history.should include(:before_save)
75
+ doc.history.should include(:after_save)
76
+ end
77
+
78
+ should "work for before and after destroy" do
79
+ doc = @document.create(:name => 'John Nunemaker')
80
+ doc.destroy
81
+ doc.history.should include(:before_destroy)
82
+ doc.history.should include(:after_destroy)
83
+ end
84
+ end
85
+ end