djsun-mongomapper 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +7 -0
  2. data/History +51 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/Rakefile +71 -0
  6. data/VERSION +1 -0
  7. data/bin/mmconsole +56 -0
  8. data/lib/mongomapper.rb +96 -0
  9. data/lib/mongomapper/associations.rb +61 -0
  10. data/lib/mongomapper/associations/base.rb +71 -0
  11. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +32 -0
  12. data/lib/mongomapper/associations/belongs_to_proxy.rb +22 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +85 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/many_embedded_proxy.rb +17 -0
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/many_proxy.rb +6 -0
  18. data/lib/mongomapper/associations/proxy.rb +67 -0
  19. data/lib/mongomapper/callbacks.rb +106 -0
  20. data/lib/mongomapper/document.rb +278 -0
  21. data/lib/mongomapper/embedded_document.rb +237 -0
  22. data/lib/mongomapper/finder_options.rb +96 -0
  23. data/lib/mongomapper/key.rb +80 -0
  24. data/lib/mongomapper/observing.rb +50 -0
  25. data/lib/mongomapper/pagination.rb +52 -0
  26. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  27. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  28. data/lib/mongomapper/save_with_validation.rb +19 -0
  29. data/lib/mongomapper/serialization.rb +55 -0
  30. data/lib/mongomapper/serializers/json_serializer.rb +79 -0
  31. data/lib/mongomapper/validations.rb +47 -0
  32. data/mongomapper.gemspec +139 -0
  33. data/test/NOTE_ON_TESTING +1 -0
  34. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +39 -0
  35. data/test/functional/associations/test_belongs_to_proxy.rb +35 -0
  36. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +131 -0
  37. data/test/functional/associations/test_many_embedded_proxy.rb +106 -0
  38. data/test/functional/associations/test_many_polymorphic_proxy.rb +267 -0
  39. data/test/functional/associations/test_many_proxy.rb +236 -0
  40. data/test/functional/test_associations.rb +40 -0
  41. data/test/functional/test_callbacks.rb +85 -0
  42. data/test/functional/test_document.rb +691 -0
  43. data/test/functional/test_pagination.rb +81 -0
  44. data/test/functional/test_rails_compatibility.rb +31 -0
  45. data/test/functional/test_validations.rb +172 -0
  46. data/test/models.rb +108 -0
  47. data/test/test_helper.rb +67 -0
  48. data/test/unit/serializers/test_json_serializer.rb +103 -0
  49. data/test/unit/test_association_base.rb +136 -0
  50. data/test/unit/test_document.rb +125 -0
  51. data/test/unit/test_embedded_document.rb +370 -0
  52. data/test/unit/test_finder_options.rb +214 -0
  53. data/test/unit/test_key.rb +217 -0
  54. data/test/unit/test_mongo_id.rb +35 -0
  55. data/test/unit/test_mongomapper.rb +28 -0
  56. data/test/unit/test_observing.rb +101 -0
  57. data/test/unit/test_pagination.rb +113 -0
  58. data/test/unit/test_rails_compatibility.rb +34 -0
  59. data/test/unit/test_serializations.rb +52 -0
  60. data/test/unit/test_validations.rb +259 -0
  61. metadata +189 -0
@@ -0,0 +1,35 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class BelongsToProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ should "default to nil" do
10
+ status = Status.new
11
+ status.project.should be_nil
12
+ end
13
+
14
+ should "be able to replace the association" do
15
+ status = Status.new
16
+ project = Project.new(:name => "mongomapper")
17
+ status.project = project
18
+ status.save.should be_true
19
+
20
+ from_db = Status.find(status.id)
21
+ from_db.project.should_not be_nil
22
+ from_db.project.name.should == "mongomapper"
23
+ end
24
+
25
+ should "unset the association" do
26
+ status = Status.new
27
+ project = Project.new(:name => "mongomapper")
28
+ status.project = project
29
+ status.save.should be_true
30
+
31
+ from_db = Status.find(status.id)
32
+ from_db.project = nil
33
+ from_db.project.should be_nil
34
+ end
35
+ end
@@ -0,0 +1,131 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyEmbeddedPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ should "default reader to empty array" do
10
+ catalog = Catalog.new
11
+ catalog.medias.should == []
12
+ end
13
+
14
+ should "allow adding to association like it was an array" do
15
+ catalog = Catalog.new
16
+ catalog.medias << Video.new
17
+ catalog.medias.push Video.new
18
+ catalog.medias.size.should == 2
19
+ end
20
+
21
+ should "be able to replace the association" do
22
+ catalog = Catalog.new
23
+ catalog.medias = [Video.new("file" => "video.mpg", "length" => 3600)]
24
+ catalog.save.should be_true
25
+
26
+ from_db = Catalog.find(catalog.id)
27
+ from_db.medias.size.should == 1
28
+ from_db.medias[0].file.should == "video.mpg"
29
+ end
30
+
31
+ should "store different associations" do
32
+ catalog = Catalog.new
33
+ catalog.medias = [
34
+ Video.new("file" => "video.mpg", "length" => 3600),
35
+ Music.new("file" => "music.mp3", "bitrate" => "128kbps"),
36
+ Image.new("file" => "image.png", "width" => 800, "height" => 600)
37
+ ]
38
+ catalog.save.should be_true
39
+
40
+ from_db = Catalog.find(catalog.id)
41
+ from_db.medias.size.should == 3
42
+ from_db.medias[0].file.should == "video.mpg"
43
+ from_db.medias[0].length.should == 3600
44
+ from_db.medias[1].file.should == "music.mp3"
45
+ from_db.medias[1].bitrate.should == "128kbps"
46
+ from_db.medias[2].file.should == "image.png"
47
+ from_db.medias[2].width.should == 800
48
+ from_db.medias[2].height.should == 600
49
+ end
50
+
51
+ context "With modularized models" do
52
+ should "set associations correctly" do
53
+ fleet_attributes = {
54
+ "name" => "My Fleet",
55
+ "transports" => [
56
+ {"_type" => "TrModels::Ambulance", "license_plate" => "GGG123", "icu" => true},
57
+ {"_type" => "TrModels::Car", "license_plate" => "ABC123", "model" => "VW Golf", "year" => 2001},
58
+ {"_type" => "TrModels::Car", "license_plate" => "DEF123", "model" => "Honda Accord", "year" => 2008},
59
+ ]
60
+ }
61
+
62
+ fleet = TrModels::Fleet.new(fleet_attributes)
63
+ fleet.transports.size.should == 3
64
+ fleet.transports[0].class.should == TrModels::Ambulance
65
+ fleet.transports[0].license_plate.should == "GGG123"
66
+ fleet.transports[0].icu.should be_true
67
+ fleet.transports[1].class.should == TrModels::Car
68
+ fleet.transports[1].license_plate.should == "ABC123"
69
+ fleet.transports[1].model.should == "VW Golf"
70
+ fleet.transports[1].year.should == 2001
71
+ fleet.transports[2].class.should == TrModels::Car
72
+ fleet.transports[2].license_plate.should == "DEF123"
73
+ fleet.transports[2].model.should == "Honda Accord"
74
+ fleet.transports[2].year.should == 2008
75
+ fleet.save.should be_true
76
+
77
+ from_db = TrModels::Fleet.find(fleet.id)
78
+ from_db.transports.size.should == 3
79
+ from_db.transports[0].license_plate.should == "GGG123"
80
+ from_db.transports[0].icu.should be_true
81
+ from_db.transports[1].license_plate.should == "ABC123"
82
+ from_db.transports[1].model.should == "VW Golf"
83
+ from_db.transports[1].year.should == 2001
84
+ from_db.transports[2].license_plate.should == "DEF123"
85
+ from_db.transports[2].model.should == "Honda Accord"
86
+ from_db.transports[2].year.should == 2008
87
+ end
88
+
89
+ should "default reader to empty array" do
90
+ fleet = TrModels::Fleet.new
91
+ fleet.transports.should == []
92
+ end
93
+
94
+ should "allow adding to association like it was an array" do
95
+ fleet = TrModels::Fleet.new
96
+ fleet.transports << TrModels::Car.new
97
+ fleet.transports.push TrModels::Bus.new
98
+ fleet.transports.size.should == 2
99
+ end
100
+
101
+ should "be able to replace the association" do
102
+ fleet = TrModels::Fleet.new
103
+ fleet.transports = [TrModels::Car.new("license_plate" => "DCU2013", "model" => "Honda Civic")]
104
+ fleet.save.should be_true
105
+
106
+ from_db = TrModels::Fleet.find(fleet.id)
107
+ from_db.transports.size.should == 1
108
+ from_db.transports[0].license_plate.should == "DCU2013"
109
+ end
110
+
111
+ should "store different associations" do
112
+ fleet = TrModels::Fleet.new
113
+ fleet.transports = [
114
+ TrModels::Car.new("license_plate" => "ABC1223", "model" => "Honda Civic", "year" => 2003),
115
+ TrModels::Bus.new("license_plate" => "XYZ9090", "max_passengers" => 51),
116
+ TrModels::Ambulance.new("license_plate" => "HDD3030", "icu" => true)
117
+ ]
118
+ fleet.save.should be_true
119
+
120
+ from_db = TrModels::Fleet.find(fleet.id)
121
+ from_db.transports.size.should == 3
122
+ from_db.transports[0].license_plate.should == "ABC1223"
123
+ from_db.transports[0].model.should == "Honda Civic"
124
+ from_db.transports[0].year.should == 2003
125
+ from_db.transports[1].license_plate.should == "XYZ9090"
126
+ from_db.transports[1].max_passengers.should == 51
127
+ from_db.transports[2].license_plate.should == "HDD3030"
128
+ from_db.transports[2].icu.should == true
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,106 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyEmbeddedProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ should "default reader to empty array" do
10
+ Project.new.addresses.should == []
11
+ end
12
+
13
+ should "allow adding to association like it was an array" do
14
+ project = Project.new
15
+ project.addresses << Address.new
16
+ project.addresses.push Address.new
17
+ project.addresses.size.should == 2
18
+ end
19
+
20
+ should "be embedded in document on save" do
21
+ sb = Address.new(:city => 'South Bend', :state => 'IN')
22
+ chi = Address.new(:city => 'Chicago', :state => 'IL')
23
+ project = Project.new
24
+ project.addresses << sb
25
+ project.addresses << chi
26
+ project.save
27
+
28
+ from_db = Project.find(project.id)
29
+ from_db.addresses.size.should == 2
30
+ from_db.addresses[0].should == sb
31
+ from_db.addresses[1].should == chi
32
+ end
33
+
34
+ should "allow embedding arbitrarily deep" do
35
+ @document = Class.new do
36
+ include MongoMapper::Document
37
+ key :person, Person
38
+ end
39
+ @document.collection.clear
40
+
41
+ meg = Person.new(:name => "Meg")
42
+ meg.child = Person.new(:name => "Steve")
43
+ meg.child.child = Person.new(:name => "Linda")
44
+
45
+ doc = @document.new(:person => meg)
46
+ doc.save
47
+
48
+ from_db = @document.find(doc.id)
49
+ from_db.person.name.should == 'Meg'
50
+ from_db.person.child.name.should == 'Steve'
51
+ from_db.person.child.child.name.should == 'Linda'
52
+ end
53
+
54
+ should "allow assignment of 'many' embedded documents using a hash" do
55
+ person_attributes = {
56
+ "name" => "Mr. Pet Lover",
57
+ "pets" => [
58
+ {"name" => "Jimmy", "species" => "Cocker Spainel"},
59
+ {"name" => "Sasha", "species" => "Siberian Husky"},
60
+ ]
61
+ }
62
+
63
+ pet_lover = RealPerson.new(person_attributes)
64
+ pet_lover.name.should == "Mr. Pet Lover"
65
+ pet_lover.pets[0].name.should == "Jimmy"
66
+ pet_lover.pets[0].species.should == "Cocker Spainel"
67
+ pet_lover.pets[1].name.should == "Sasha"
68
+ pet_lover.pets[1].species.should == "Siberian Husky"
69
+ pet_lover.save.should be_true
70
+
71
+ from_db = RealPerson.find(pet_lover.id)
72
+ from_db.name.should == "Mr. Pet Lover"
73
+ from_db.pets[0].name.should == "Jimmy"
74
+ from_db.pets[0].species.should == "Cocker Spainel"
75
+ from_db.pets[1].name.should == "Sasha"
76
+ from_db.pets[1].species.should == "Siberian Husky"
77
+ end
78
+
79
+ should "allow saving embedded documents in 'many' embedded documents" do
80
+ @document = Class.new do
81
+ include MongoMapper::Document
82
+ many :people
83
+ end
84
+ @document.collection.clear
85
+
86
+ meg = Person.new(:name => "Meg")
87
+ sparky = Pet.new(:name => "Sparky", :species => "Dog")
88
+ koda = Pet.new(:name => "Koda", :species => "Dog")
89
+
90
+ doc = @document.new
91
+
92
+ meg.pets << sparky
93
+ meg.pets << koda
94
+
95
+ doc.people << meg
96
+ doc.save
97
+
98
+ from_db = @document.find(doc.id)
99
+ from_db.people.first.name.should == "Meg"
100
+ from_db.people.first.pets.should_not == []
101
+ from_db.people.first.pets.first.name.should == "Sparky"
102
+ from_db.people.first.pets.first.species.should == "Dog"
103
+ from_db.people.first.pets[1].name.should == "Koda"
104
+ from_db.people.first.pets[1].species.should == "Dog"
105
+ end
106
+ end
@@ -0,0 +1,267 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyPolymorphicProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ should "default reader to empty array" do
10
+ Room.new.messages.should == []
11
+ end
12
+
13
+ should "add type key to polymorphic class base" do
14
+ Message.keys.keys.should include('_type')
15
+ end
16
+
17
+ should "allow adding to assiciation like it was an array" do
18
+ room = Room.new
19
+ room.messages << Enter.new
20
+ room.messages.push Exit.new
21
+ room.messages.concat Exit.new
22
+ room.messages.size.should == 3
23
+ end
24
+
25
+ should "be able to replace the association" do
26
+ room = Room.create(:name => 'Lounge')
27
+
28
+ lambda {
29
+ room.messages = [
30
+ Enter.new(:body => 'John entered room'),
31
+ Chat.new(:body => 'Heyyyoooo!'),
32
+ Exit.new(:body => 'John exited room')
33
+ ]
34
+ }.should change { Message.count }.by(3)
35
+
36
+ from_db = Room.find(room.id)
37
+ from_db.messages.size.should == 3
38
+ from_db.messages[0].body.should == 'John entered room'
39
+ from_db.messages[1].body.should == 'Heyyyoooo!'
40
+ from_db.messages[2].body.should == 'John exited room'
41
+ end
42
+
43
+ # Intermittent failure (DJ, 2009-08-03)
44
+ should_eventually "correctly store type when using <<, push and concat" do
45
+ room = Room.new
46
+ room.messages << Enter.new(:body => 'John entered the room')
47
+ room.messages.push Exit.new(:body => 'John entered the room')
48
+ room.messages.concat Chat.new(:body => 'Holla!')
49
+
50
+ from_db = Room.find(room.id)
51
+ from_db.messages[0]._type.should == 'Enter'
52
+ from_db.messages[1]._type.should == 'Exit'
53
+ from_db.messages[2]._type.should == 'Chat'
54
+ end
55
+
56
+ context "build" do
57
+ should "assign foreign key" do
58
+ room = Room.create
59
+ message = room.messages.build
60
+ message.room_id.should == room.id
61
+ end
62
+
63
+ should "assign _type" do
64
+ room = Room.create
65
+ message = room.messages.build
66
+ message._type.should == 'Message'
67
+ end
68
+
69
+ should "allow assigning attributes" do
70
+ room = Room.create
71
+ message = room.messages.build(:body => 'Foo!')
72
+ message.body.should == 'Foo!'
73
+ end
74
+ end
75
+
76
+ context "create" do
77
+ should "assign foreign key" do
78
+ room = Room.create
79
+ message = room.messages.create
80
+ message.room_id.should == room.id
81
+ end
82
+
83
+ should "assign _type" do
84
+ room = Room.create
85
+ message = room.messages.create
86
+ message._type.should == 'Message'
87
+ end
88
+
89
+ should "save record" do
90
+ room = Room.create
91
+ lambda {
92
+ room.messages.create
93
+ }.should change { Message.count }
94
+ end
95
+
96
+ should "allow passing attributes" do
97
+ room = Room.create
98
+ message = room.messages.create(:body => 'Foo!')
99
+ message.body.should == 'Foo!'
100
+ end
101
+ end
102
+
103
+ context "count" do
104
+ should "work scoped to association" do
105
+ room = Room.create
106
+ 3.times { room.messages.create }
107
+
108
+ other_room = Room.create
109
+ 2.times { other_room.messages.create }
110
+
111
+ room.messages.count.should == 3
112
+ other_room.messages.count.should == 2
113
+ end
114
+
115
+ should "work with conditions" do
116
+ room = Room.create
117
+ room.messages.create(:body => 'Foo')
118
+ room.messages.create(:body => 'Other 1')
119
+ room.messages.create(:body => 'Other 2')
120
+
121
+ room.messages.count(:body => 'Foo').should == 1
122
+ end
123
+ end
124
+
125
+ context "Finding scoped to association" do
126
+ setup do
127
+ @lounge = Room.create(:name => 'Lounge')
128
+ @lm1 = Message.create(:body => 'Loungin!')
129
+ @lm2 = Message.create(:body => 'I love loungin!')
130
+ @lounge.messages = [@lm1, @lm2]
131
+ @lounge.save
132
+
133
+ @hall = Room.create(:name => 'Hall')
134
+ @hm1 = Message.create(:body => 'Do not fall in the hall')
135
+ @hm2 = Message.create(:body => 'Hall the king!')
136
+ @hm3 = Message.create(:body => 'Loungin!')
137
+ @hall.messages = [@hm1, @hm2, @hm3]
138
+ @hall.save
139
+ end
140
+
141
+ context "with :all" do
142
+ # Intermittent failure (DJ, 2009-08-03)
143
+ should_eventually "work" do
144
+ @lounge.messages.find(:all).should == [@lm1, @lm2]
145
+ end
146
+
147
+ should "work with conditions" do
148
+ messages = @lounge.messages.find(:all, :conditions => {:body => 'Loungin!'})
149
+ messages.should == [@lm1]
150
+ end
151
+
152
+ # Intermittent failure (DJ, 2009-08-03)
153
+ should_eventually "work with order" do
154
+ messages = @lounge.messages.find(:all, :order => '$natural desc')
155
+ messages.should == [@lm2, @lm1]
156
+ end
157
+ end
158
+
159
+ context "with #all" do
160
+ should "work" do
161
+ @lounge.messages.all.should == [@lm1, @lm2]
162
+ end
163
+
164
+ should "work with conditions" do
165
+ messages = @lounge.messages.all(:conditions => {'body' => 'Loungin!'})
166
+ messages.should == [@lm1]
167
+ end
168
+
169
+ # Intermittent failure (DJ, 2009-08-03)
170
+ should_eventually "work with order" do
171
+ messages = @lounge.messages.all(:order => '$natural desc')
172
+ messages.should == [@lm2, @lm1]
173
+ end
174
+ end
175
+
176
+ context "with :first" do
177
+ # Intermittent failure (DJ, 2009-08-03)
178
+ should_eventually "work" do
179
+ @lounge.messages.find(:first).should == @lm1
180
+ end
181
+
182
+ should "work with conditions" do
183
+ message = @lounge.messages.find(:first, :conditions => {:body => 'I love loungin!'})
184
+ message.should == @lm2
185
+ end
186
+ end
187
+
188
+ context "with #first" do
189
+ # Intermittent failure (DJ, 2009-08-03)
190
+ should_eventually "work" do
191
+ @lounge.messages.first.should == @lm1
192
+ end
193
+
194
+ should "work with conditions" do
195
+ message = @lounge.messages.first(:conditions => {:body => 'I love loungin!'})
196
+ message.should == @lm2
197
+ end
198
+ end
199
+
200
+ context "with :last" do
201
+ should "work" do
202
+ @lounge.messages.find(:last).should == @lm2
203
+ end
204
+
205
+ should "work with conditions" do
206
+ message = @lounge.messages.find(:last, :conditions => {:body => 'Loungin!'})
207
+ message.should == @lm1
208
+ end
209
+ end
210
+
211
+ context "with #last" do
212
+ # Intermittent failure (DJ, 2009-08-03)
213
+ should_eventually "work" do
214
+ @lounge.messages.last.should == @lm2
215
+ end
216
+
217
+ should "work with conditions" do
218
+ message = @lounge.messages.last(:conditions => {:body => 'Loungin!'})
219
+ message.should == @lm1
220
+ end
221
+ end
222
+
223
+ context "with one id" do
224
+ should "work for id in association" do
225
+ @lounge.messages.find(@lm2.id).should == @lm2
226
+ end
227
+
228
+ should "not work for id not in association" do
229
+ lambda {
230
+ @lounge.messages.find(@hm2.id)
231
+ }.should raise_error(MongoMapper::DocumentNotFound)
232
+ end
233
+ end
234
+
235
+ context "with multiple ids" do
236
+ should "work for ids in association" do
237
+ messages = @lounge.messages.find(@lm1.id, @lm2.id)
238
+ messages.should == [@lm1, @lm2]
239
+ end
240
+
241
+ should "not work for ids not in association" do
242
+ lambda {
243
+ @lounge.messages.find(@lm1.id, @lm2.id, @hm2.id)
244
+ }.should raise_error(MongoMapper::DocumentNotFound)
245
+ end
246
+ end
247
+
248
+ context "with #paginate" do
249
+ setup do
250
+ @messages = @hall.messages.paginate(:per_page => 2, :page => 1, :order => '$natural asc')
251
+ end
252
+
253
+ should "return total pages" do
254
+ @messages.total_pages.should == 2
255
+ end
256
+
257
+ should "return total entries" do
258
+ @messages.total_entries.should == 3
259
+ end
260
+
261
+ # Intermittent failure (DJ, 2009-08-03)
262
+ should_eventually "return the subject" do
263
+ @messages.should == [@hm1, @hm2]
264
+ end
265
+ end
266
+ end
267
+ end