crnixon-mongomapper 0.2.0 → 0.3.4

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 (68) hide show
  1. data/.gitignore +1 -0
  2. data/History +48 -0
  3. data/README.rdoc +5 -3
  4. data/Rakefile +6 -4
  5. data/VERSION +1 -1
  6. data/bin/mmconsole +56 -0
  7. data/lib/mongomapper.rb +29 -18
  8. data/lib/mongomapper/associations.rb +53 -38
  9. data/lib/mongomapper/associations/base.rb +53 -20
  10. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
  12. data/lib/mongomapper/associations/many_documents_as_proxy.rb +27 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +103 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +6 -8
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/{array_proxy.rb → many_proxy.rb} +1 -1
  18. data/lib/mongomapper/associations/proxy.rb +24 -21
  19. data/lib/mongomapper/callbacks.rb +1 -1
  20. data/lib/mongomapper/document.rb +160 -74
  21. data/lib/mongomapper/dynamic_finder.rb +38 -0
  22. data/lib/mongomapper/embedded_document.rb +154 -105
  23. data/lib/mongomapper/finder_options.rb +11 -7
  24. data/lib/mongomapper/key.rb +15 -21
  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/serialization.rb +1 -1
  29. data/lib/mongomapper/serializers/json_serializer.rb +15 -0
  30. data/lib/mongomapper/support.rb +30 -0
  31. data/mongomapper.gemspec +87 -46
  32. data/test/NOTE_ON_TESTING +1 -0
  33. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -0
  34. data/test/functional/associations/test_belongs_to_proxy.rb +45 -0
  35. data/test/functional/associations/test_many_documents_as_proxy.rb +253 -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 +261 -0
  39. data/test/functional/associations/test_many_proxy.rb +295 -0
  40. data/test/functional/test_associations.rb +47 -0
  41. data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
  42. data/test/functional/test_document.rb +952 -0
  43. data/test/functional/test_pagination.rb +81 -0
  44. data/test/functional/test_rails_compatibility.rb +30 -0
  45. data/test/functional/test_validations.rb +172 -0
  46. data/test/models.rb +169 -0
  47. data/test/test_helper.rb +7 -2
  48. data/test/unit/serializers/test_json_serializer.rb +189 -0
  49. data/test/unit/test_association_base.rb +144 -0
  50. data/test/unit/test_document.rb +123 -0
  51. data/test/unit/test_embedded_document.rb +526 -0
  52. data/test/{test_finder_options.rb → unit/test_finder_options.rb} +36 -1
  53. data/test/{test_key.rb → unit/test_key.rb} +59 -12
  54. data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
  55. data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
  56. data/test/unit/test_pagination.rb +113 -0
  57. data/test/unit/test_rails_compatibility.rb +34 -0
  58. data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
  59. data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
  60. metadata +81 -43
  61. data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
  62. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
  63. data/lib/mongomapper/rails_compatibility.rb +0 -23
  64. data/test/serializers/test_json_serializer.rb +0 -104
  65. data/test/test_associations.rb +0 -174
  66. data/test/test_document.rb +0 -944
  67. data/test/test_embedded_document.rb +0 -253
  68. data/test/test_rails_compatibility.rb +0 -29
@@ -0,0 +1,253 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyDocumentsAsProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ should "default reader to empty array" do
10
+ Post.new.comments.should == []
11
+ end
12
+
13
+ should "add type and id key to polymorphic class base" do
14
+ PostComment.keys.keys.should include('commentable_type')
15
+ PostComment.keys.keys.should include('commentable_id')
16
+ end
17
+
18
+ should "allow adding to association like it was an array" do
19
+ post = Post.new
20
+ post.comments << PostComment.new(:body => 'foo bar')
21
+ post.comments << PostComment.new(:body => 'baz')
22
+ post.comments.concat PostComment.new(:body => 'baz')
23
+
24
+ post.comments.size.should == 3
25
+ end
26
+
27
+ should "be able to replace the association" do
28
+ post = Post.new
29
+
30
+ lambda {
31
+ post.comments = [
32
+ PostComment.new(:body => 'foo'),
33
+ PostComment.new(:body => 'bar'),
34
+ PostComment.new(:body => 'baz')
35
+ ]
36
+ }.should change { PostComment.count }.by(3)
37
+
38
+ from_db = Post.find(post.id)
39
+ from_db.comments.size.should == 3
40
+ from_db.comments[0].body.should == 'foo'
41
+ from_db.comments[1].body.should == 'bar'
42
+ from_db.comments[2].body.should == 'baz'
43
+ end
44
+
45
+ context "build" do
46
+ should "assign foreign key" do
47
+ post = Post.new
48
+ comment = post.comments.build
49
+ comment.commentable_id.should == post.id
50
+ end
51
+
52
+ should "assign _type" do
53
+ post = Post.new
54
+ comment = post.comments.build
55
+ comment.commentable_type.should == "Post"
56
+ end
57
+
58
+ should "allow assigning attributes" do
59
+ post = Post.new
60
+ comment = post.comments.build(:body => 'foo bar')
61
+ comment.body.should == 'foo bar'
62
+ end
63
+ end
64
+
65
+ context "create" do
66
+ should "assign foreign key" do
67
+ post = Post.new
68
+ comment = post.comments.create
69
+ comment.commentable_id.should == post.id
70
+ end
71
+
72
+ should "assign _type" do
73
+ post = Post.new
74
+ comment = post.comments.create
75
+ comment.commentable_type.should == "Post"
76
+ end
77
+
78
+ should "save record" do
79
+ post = Post.new
80
+ lambda {
81
+ post.comments.create(:body => 'baz')
82
+ }.should change { PostComment.count }
83
+ end
84
+
85
+ should "allow passing attributes" do
86
+ post = Post.create
87
+ comment = post.comments.create(:body => 'foo bar')
88
+ comment.body.should == 'foo bar'
89
+ end
90
+ end
91
+
92
+ context "count" do
93
+ should "work scoped to association" do
94
+ post = Post.create
95
+ 3.times { post.comments.create(:body => 'foo bar') }
96
+
97
+ other_post = Post.create
98
+ 2.times { other_post.comments.create(:body => 'baz') }
99
+
100
+ post.comments.count.should == 3
101
+ other_post.comments.count.should == 2
102
+ end
103
+
104
+ should "work with conditions" do
105
+ post = Post.create
106
+ post.comments.create(:body => 'foo bar')
107
+ post.comments.create(:body => 'baz')
108
+ post.comments.create(:body => 'foo bar')
109
+
110
+ post.comments.count(:body => 'foo bar').should == 2
111
+ end
112
+ end
113
+
114
+ context "Finding scoped to association" do
115
+ setup do
116
+ @post = Post.new
117
+
118
+ @comment1 = PostComment.create(:body => 'comment1')
119
+ @comment2 = PostComment.create(:body => 'comment2')
120
+ @comment3 = PostComment.create(:body => 'comment3')
121
+ @post.comments = [@comment1, @comment2]
122
+ @post.save
123
+
124
+ @post2 = Post.create(:body => "post #2")
125
+ @comment4 = PostComment.create(:body => 'comment4')
126
+ @comment5 = PostComment.create(:body => 'comment5')
127
+ @comment6 = PostComment.create(:body => 'comment6')
128
+ @post2.comments = [@comment4, @comment5, @comment6]
129
+ @post2.save
130
+ end
131
+
132
+ context "with :all" do
133
+ should "work" do
134
+ @post.comments.find(:all).should include(@comment1)
135
+ @post.comments.find(:all).should include(@comment2)
136
+ end
137
+
138
+ should "work with conditions" do
139
+ comments = @post.comments.find(:all, :conditions => {:body => 'comment1'})
140
+ comments.should == [@comment1]
141
+ end
142
+
143
+ should "work with order" do
144
+ comments = @post.comments.find(:all, :order => '$natural desc')
145
+ comments.should == [@comment2, @comment1]
146
+ end
147
+ end
148
+
149
+ context "with #all" do
150
+ should "work" do
151
+ @post.comments.all.should == [@comment1, @comment2]
152
+ end
153
+
154
+ should "work with conditions" do
155
+ comments = @post.comments.all(:conditions => {:body => 'comment1'})
156
+ comments.should == [@comment1]
157
+ end
158
+
159
+ should "work with order" do
160
+ comments = @post.comments.all(:order => '$natural desc')
161
+ comments.should == [@comment2, @comment1]
162
+ end
163
+ end
164
+
165
+ context "with :first" do
166
+ should "work" do
167
+ lambda {@post.comments.find(:first)}.should_not raise_error
168
+ end
169
+
170
+ should "work with conditions" do
171
+ comment = @post.comments.find(:first, :conditions => {:body => 'comment2'})
172
+ comment.body.should == 'comment2'
173
+ end
174
+ end
175
+
176
+ context "with #first" do
177
+ should "work" do
178
+ @post.comments.first.should == @comment1
179
+ end
180
+
181
+ should "work with conditions" do
182
+ comment = @post.comments.first(:conditions => {:body => 'comment2'})
183
+ comment.should == @comment2
184
+ end
185
+ end
186
+
187
+ context "with :last" do
188
+ should "work" do
189
+ @post.comments.find(:last, :order => 'created_at asc').should == @comment2
190
+ end
191
+
192
+ should "work with conditions" do
193
+ post = @post.comments.find(:last, :conditions => {:body => 'comment1'})
194
+ post.body.should == 'comment1'
195
+ end
196
+ end
197
+
198
+ context "with #last" do
199
+ should "work" do
200
+ @post.comments.last.should == @comment2
201
+ end
202
+
203
+ should "work with conditions" do
204
+ comment = @post.comments.last(:conditions => {:body => 'comment1'})
205
+ comment.should == @comment1
206
+ end
207
+ end
208
+
209
+ context "with one id" do
210
+ should "work for id in association" do
211
+ @post.comments.find(@comment2.id).should == @comment2
212
+ end
213
+
214
+ should "not work for id not in association" do
215
+ lambda {
216
+ @post.comments.find(@comment5.id)
217
+ }.should raise_error(MongoMapper::DocumentNotFound)
218
+ end
219
+ end
220
+
221
+ context "with multiple ids" do
222
+ should "work for ids in association" do
223
+ posts = @post.comments.find(@comment1.id, @comment2.id)
224
+ posts.should == [@comment1, @comment2]
225
+ end
226
+
227
+ should "not work for ids not in association" do
228
+ lambda {
229
+ @post.comments.find(@comment1.id, @comment2.id, @comment4.id)
230
+ }.should raise_error(MongoMapper::DocumentNotFound)
231
+ end
232
+ end
233
+
234
+ context "with #paginate" do
235
+ setup do
236
+ @comments = @post2.comments.paginate(:per_page => 2, :page => 1, :order => 'created_at asc')
237
+ end
238
+
239
+ should "return total pages" do
240
+ @comments.total_pages.should == 2
241
+ end
242
+
243
+ should "return total entries" do
244
+ @comments.total_entries.should == 3
245
+ end
246
+
247
+ should "return the subject" do
248
+ @comments.should include(@comment4)
249
+ @comments.should include(@comment5)
250
+ end
251
+ end
252
+ end
253
+ 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