djsun-mongomapper 0.3.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 (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