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,261 @@
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', :position => 1),
31
+ Chat.new(:body => 'Heyyyoooo!', :position => 2),
32
+ Exit.new(:body => 'John exited room', :position => 3)
33
+ ]
34
+ }.should change { Message.count }.by(3)
35
+
36
+ from_db = Room.find(room.id)
37
+ messages = from_db.messages.all :order => "position"
38
+ messages.size.should == 3
39
+ messages[0].body.should == 'John entered room'
40
+ messages[1].body.should == 'Heyyyoooo!'
41
+ messages[2].body.should == 'John exited room'
42
+ end
43
+
44
+ should "correctly store type when using <<, push and concat" do
45
+ room = Room.new
46
+ room.messages << Enter.new(:body => 'John entered the room', :position => 1)
47
+ room.messages.push Exit.new(:body => 'John entered the room', :position => 2)
48
+ room.messages.concat Chat.new(:body => 'Holla!' , :position => 3)
49
+
50
+ from_db = Room.find(room.id)
51
+ messages = from_db.messages.all :order => "position"
52
+ messages[0]._type.should == 'Enter'
53
+ messages[1]._type.should == 'Exit'
54
+ messages[2]._type.should == 'Chat'
55
+ end
56
+
57
+ context "build" do
58
+ should "assign foreign key" do
59
+ room = Room.create
60
+ message = room.messages.build
61
+ message.room_id.should == room.id
62
+ end
63
+
64
+ should "assign _type" do
65
+ room = Room.create
66
+ message = room.messages.build
67
+ message._type.should == 'Message'
68
+ end
69
+
70
+ should "allow assigning attributes" do
71
+ room = Room.create
72
+ message = room.messages.build(:body => 'Foo!')
73
+ message.body.should == 'Foo!'
74
+ end
75
+ end
76
+
77
+ context "create" do
78
+ should "assign foreign key" do
79
+ room = Room.create
80
+ message = room.messages.create
81
+ message.room_id.should == room.id
82
+ end
83
+
84
+ should "assign _type" do
85
+ room = Room.create
86
+ message = room.messages.create
87
+ message._type.should == 'Message'
88
+ end
89
+
90
+ should "save record" do
91
+ room = Room.create
92
+ lambda {
93
+ room.messages.create
94
+ }.should change { Message.count }
95
+ end
96
+
97
+ should "allow passing attributes" do
98
+ room = Room.create
99
+ message = room.messages.create(:body => 'Foo!')
100
+ message.body.should == 'Foo!'
101
+ end
102
+ end
103
+
104
+ context "count" do
105
+ should "work scoped to association" do
106
+ room = Room.create
107
+ 3.times { room.messages.create }
108
+
109
+ other_room = Room.create
110
+ 2.times { other_room.messages.create }
111
+
112
+ room.messages.count.should == 3
113
+ other_room.messages.count.should == 2
114
+ end
115
+
116
+ should "work with conditions" do
117
+ room = Room.create
118
+ room.messages.create(:body => 'Foo')
119
+ room.messages.create(:body => 'Other 1')
120
+ room.messages.create(:body => 'Other 2')
121
+
122
+ room.messages.count(:body => 'Foo').should == 1
123
+ end
124
+ end
125
+
126
+ context "Finding scoped to association" do
127
+ setup do
128
+ @lounge = Room.create(:name => 'Lounge')
129
+ @lm1 = Message.create(:body => 'Loungin!', :position => 1)
130
+ @lm2 = Message.create(:body => 'I love loungin!', :position => 2)
131
+ @lounge.messages = [@lm1, @lm2]
132
+ @lounge.save
133
+
134
+ @hall = Room.create(:name => 'Hall')
135
+ @hm1 = Message.create(:body => 'Do not fall in the hall', :position => 1)
136
+ @hm2 = Message.create(:body => 'Hall the king!', :position => 2)
137
+ @hm3 = Message.create(:body => 'Loungin!', :position => 3)
138
+ @hall.messages = [@hm1, @hm2, @hm3]
139
+ @hall.save
140
+ end
141
+
142
+ context "with :all" do
143
+ should "work" do
144
+ @lounge.messages.find(:all, :order => "position").should == [@lm1, @lm2]
145
+ end
146
+
147
+ should "work with conditions" do
148
+ messages = @lounge.messages.find(:all, :conditions => {:body => 'Loungin!'}, :order => "position")
149
+ messages.should == [@lm1]
150
+ end
151
+
152
+ should "work with order" do
153
+ messages = @lounge.messages.find(:all, :order => 'position desc')
154
+ messages.should == [@lm2, @lm1]
155
+ end
156
+ end
157
+
158
+ context "with #all" do
159
+ should "work" do
160
+ @lounge.messages.all(:order => "position").should == [@lm1, @lm2]
161
+ end
162
+
163
+ should "work with conditions" do
164
+ messages = @lounge.messages.all(:conditions => {:body => 'Loungin!'}, :order => "position")
165
+ messages.should == [@lm1]
166
+ end
167
+
168
+ should "work with order" do
169
+ messages = @lounge.messages.all(:order => 'position desc')
170
+ messages.should == [@lm2, @lm1]
171
+ end
172
+ end
173
+
174
+ context "with :first" do
175
+ should "work" do
176
+ @lounge.messages.find(:first, :order => "position asc").should == @lm1
177
+ end
178
+
179
+ should "work with conditions" do
180
+ message = @lounge.messages.find(:first, :conditions => {:body => 'I love loungin!'}, :order => "position asc")
181
+ message.should == @lm2
182
+ end
183
+ end
184
+
185
+ context "with #first" do
186
+ should "work" do
187
+ @lounge.messages.first(:order => "position asc").should == @lm1
188
+ end
189
+
190
+ should "work with conditions" do
191
+ message = @lounge.messages.first(:conditions => {:body => 'I love loungin!'}, :order => "position asc")
192
+ message.should == @lm2
193
+ end
194
+ end
195
+
196
+ context "with :last" do
197
+ should "work" do
198
+ @lounge.messages.find(:last, :order => "position asc").should == @lm2
199
+ end
200
+
201
+ should "work with conditions" do
202
+ message = @lounge.messages.find(:last, :conditions => {:body => 'Loungin!'}, :order => "position asc")
203
+ message.should == @lm1
204
+ end
205
+ end
206
+
207
+ context "with #last" do
208
+ should "work" do
209
+ @lounge.messages.last(:order => "position asc").should == @lm2
210
+ end
211
+
212
+ should "work with conditions" do
213
+ message = @lounge.messages.last(:conditions => {:body => 'Loungin!'}, :order => "position asc")
214
+ message.should == @lm1
215
+ end
216
+ end
217
+
218
+ context "with one id" do
219
+ should "work for id in association" do
220
+ @lounge.messages.find(@lm2.id).should == @lm2
221
+ end
222
+
223
+ should "not work for id not in association" do
224
+ lambda {
225
+ @lounge.messages.find(@hm2.id)
226
+ }.should raise_error(MongoMapper::DocumentNotFound)
227
+ end
228
+ end
229
+
230
+ context "with multiple ids" do
231
+ should "work for ids in association" do
232
+ messages = @lounge.messages.find(@lm1.id, @lm2.id)
233
+ messages.should == [@lm1, @lm2]
234
+ end
235
+
236
+ should "not work for ids not in association" do
237
+ lambda {
238
+ @lounge.messages.find(@lm1.id, @lm2.id, @hm2.id)
239
+ }.should raise_error(MongoMapper::DocumentNotFound)
240
+ end
241
+ end
242
+
243
+ context "with #paginate" do
244
+ setup do
245
+ @messages = @hall.messages.paginate(:per_page => 2, :page => 1, :order => 'position asc')
246
+ end
247
+
248
+ should "return total pages" do
249
+ @messages.total_pages.should == 2
250
+ end
251
+
252
+ should "return total entries" do
253
+ @messages.total_entries.should == 3
254
+ end
255
+
256
+ should "return the subject" do
257
+ @messages.should == [@hm1, @hm2]
258
+ end
259
+ end
260
+ end
261
+ end
@@ -0,0 +1,295 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class ManyProxyTest < Test::Unit::TestCase
5
+ def setup
6
+ clear_all_collections
7
+ end
8
+
9
+ should "default reader to empty array" do
10
+ project = Project.new
11
+ project.statuses.should == []
12
+ end
13
+
14
+ should "allow adding to association like it was an array" do
15
+ project = Project.new
16
+ project.statuses << Status.new
17
+ project.statuses.push Status.new
18
+ project.statuses.concat Status.new
19
+ project.statuses.size.should == 3
20
+ end
21
+
22
+ should "be able to replace the association" do
23
+ project = Project.new
24
+ project.statuses = [Status.new("name" => "ready")]
25
+ project.save.should be_true
26
+
27
+ from_db = Project.find(project.id)
28
+ from_db.statuses.size.should == 1
29
+ from_db.statuses[0].name.should == "ready"
30
+ end
31
+
32
+ should "correctly assign foreign key when using <<, push and concat" do
33
+ project = Project.new
34
+ project.statuses << Status.new(:name => '<<')
35
+ project.statuses.push Status.new(:name => 'push')
36
+ project.statuses.concat Status.new(:name => 'concat')
37
+
38
+ from_db = Project.find(project.id)
39
+ from_db.statuses[0].project_id.should == project.id
40
+ from_db.statuses[1].project_id.should == project.id
41
+ from_db.statuses[2].project_id.should == project.id
42
+ end
43
+
44
+ context "build" do
45
+ should "assign foreign key" do
46
+ project = Project.create
47
+ status = project.statuses.build
48
+ status.project_id.should == project.id
49
+ end
50
+
51
+ should "allow assigning attributes" do
52
+ project = Project.create
53
+ status = project.statuses.build(:name => 'Foo')
54
+ status.name.should == 'Foo'
55
+ end
56
+ end
57
+
58
+ context "create" do
59
+ should "assign foreign key" do
60
+ project = Project.create
61
+ status = project.statuses.create
62
+ status.project_id.should == project.id
63
+ end
64
+
65
+ should "save record" do
66
+ project = Project.create
67
+ lambda {
68
+ project.statuses.create
69
+ }.should change { Status.count }
70
+ end
71
+
72
+ should "allow passing attributes" do
73
+ project = Project.create
74
+ status = project.statuses.create(:name => 'Foo!')
75
+ status.name.should == 'Foo!'
76
+ end
77
+ end
78
+
79
+ context "count" do
80
+ should "work scoped to association" do
81
+ project = Project.create
82
+ 3.times { project.statuses.create }
83
+
84
+ other_project = Project.create
85
+ 2.times { other_project.statuses.create }
86
+
87
+ project.statuses.count.should == 3
88
+ other_project.statuses.count.should == 2
89
+ end
90
+
91
+ should "work with conditions" do
92
+ project = Project.create
93
+ project.statuses.create(:name => 'Foo')
94
+ project.statuses.create(:name => 'Other 1')
95
+ project.statuses.create(:name => 'Other 2')
96
+
97
+ project.statuses.count(:name => 'Foo').should == 1
98
+ end
99
+ end
100
+
101
+ context "Unassociating documents" do
102
+ setup do
103
+ @project = Project.create
104
+ @project.statuses << Status.create(:name => '1')
105
+ @project.statuses << Status.create(:name => '2')
106
+
107
+ @project2 = Project.create
108
+ @project2.statuses << Status.create(:name => '1')
109
+ @project2.statuses << Status.create(:name => '2')
110
+ end
111
+
112
+ should "work with destroy all" do
113
+ @project.statuses.count.should == 2
114
+ @project.statuses.destroy_all
115
+ @project.statuses.count.should == 0
116
+
117
+ @project2.statuses.count.should == 2
118
+ Status.count.should == 2
119
+ end
120
+
121
+ should "work with destroy all and conditions" do
122
+ @project.statuses.count.should == 2
123
+ @project.statuses.destroy_all(:name => '1')
124
+ @project.statuses.count.should == 1
125
+
126
+ @project2.statuses.count.should == 2
127
+ Status.count.should == 3
128
+ end
129
+
130
+ should "work with delete all" do
131
+ @project.statuses.count.should == 2
132
+ @project.statuses.delete_all
133
+ @project.statuses.count.should == 0
134
+
135
+ @project2.statuses.count.should == 2
136
+ Status.count.should == 2
137
+ end
138
+
139
+ should "work with delete all and conditions" do
140
+ @project.statuses.count.should == 2
141
+ @project.statuses.delete_all(:name => '1')
142
+ @project.statuses.count.should == 1
143
+
144
+ @project2.statuses.count.should == 2
145
+ Status.count.should == 3
146
+ end
147
+
148
+ should "work with nullify" do
149
+ @project.statuses.count.should == 2
150
+ @project.statuses.nullify
151
+ @project.statuses.count.should == 0
152
+
153
+ @project2.statuses.count.should == 2
154
+ Status.count.should == 4
155
+ Status.count(:name => '1').should == 2
156
+ Status.count(:name => '2').should == 2
157
+ end
158
+ end
159
+
160
+ context "Finding scoped to association" do
161
+ setup do
162
+ @project1 = Project.new(:name => 'Project 1')
163
+ @brand_new = Status.create(:name => 'New', :position => 1 )
164
+ @complete = Status.create(:name => 'Complete', :position => 2)
165
+ @project1.statuses = [@brand_new, @complete]
166
+ @project1.save
167
+
168
+ @project2 = Project.create(:name => 'Project 2')
169
+ @in_progress = Status.create(:name => 'In Progress')
170
+ @archived = Status.create(:name => 'Archived')
171
+ @another_complete = Status.create(:name => 'Complete')
172
+ @project2.statuses = [@in_progress, @archived, @another_complete]
173
+ @project2.save
174
+ end
175
+
176
+ context "with :all" do
177
+ should "work" do
178
+ @project1.statuses.find(:all, :order => "position asc").should == [@brand_new, @complete]
179
+ end
180
+
181
+ should "work with conditions" do
182
+ statuses = @project1.statuses.find(:all, :conditions => {'name' => 'Complete'})
183
+ statuses.should == [@complete]
184
+ end
185
+
186
+ should "work with order" do
187
+ statuses = @project1.statuses.find(:all, :order => 'name asc')
188
+ statuses.should == [@complete, @brand_new]
189
+ end
190
+ end
191
+
192
+ context "with #all" do
193
+ should "work" do
194
+ @project1.statuses.all(:order => "position asc").should == [@brand_new, @complete]
195
+ end
196
+
197
+ should "work with conditions" do
198
+ statuses = @project1.statuses.all(:conditions => {'name' => 'Complete'})
199
+ statuses.should == [@complete]
200
+ end
201
+
202
+ should "work with order" do
203
+ statuses = @project1.statuses.all(:order => 'name asc')
204
+ statuses.should == [@complete, @brand_new]
205
+ end
206
+ end
207
+
208
+ context "with :first" do
209
+ should "work" do
210
+ @project1.statuses.find(:first, :order => 'name').should == @complete
211
+ end
212
+
213
+ should "work with conditions" do
214
+ status = @project1.statuses.find(:first, :conditions => {:name => 'Complete'})
215
+ status.should == @complete
216
+ end
217
+ end
218
+
219
+ context "with #first" do
220
+ should "work" do
221
+ @project1.statuses.first(:order => 'name').should == @complete
222
+ end
223
+
224
+ should "work with conditions" do
225
+ status = @project1.statuses.first(:conditions => {:name => 'Complete'})
226
+ status.should == @complete
227
+ end
228
+ end
229
+
230
+ context "with :last" do
231
+ should "work" do
232
+ @project1.statuses.find(:last, :order => "position asc").should == @complete
233
+ end
234
+
235
+ should "work with conditions" do
236
+ status = @project1.statuses.find(:last, :conditions => {:name => 'New'})
237
+ status.should == @brand_new
238
+ end
239
+ end
240
+
241
+ context "with #last" do
242
+ should "work" do
243
+ @project1.statuses.last(:order => "position asc").should == @complete
244
+ end
245
+
246
+ should "work with conditions" do
247
+ status = @project1.statuses.last(:conditions => {:name => 'New'})
248
+ status.should == @brand_new
249
+ end
250
+ end
251
+
252
+ context "with one id" do
253
+ should "work for id in association" do
254
+ @project1.statuses.find(@complete.id).should == @complete
255
+ end
256
+
257
+ should "not work for id not in association" do
258
+ lambda {
259
+ @project1.statuses.find(@archived.id)
260
+ }.should raise_error(MongoMapper::DocumentNotFound)
261
+ end
262
+ end
263
+
264
+ context "with multiple ids" do
265
+ should "work for ids in association" do
266
+ statuses = @project1.statuses.find(@brand_new.id, @complete.id)
267
+ statuses.should == [@brand_new, @complete]
268
+ end
269
+
270
+ should "not work for ids not in association" do
271
+ lambda {
272
+ @project1.statuses.find(@brand_new.id, @complete.id, @archived.id)
273
+ }.should raise_error(MongoMapper::DocumentNotFound)
274
+ end
275
+ end
276
+
277
+ context "with #paginate" do
278
+ setup do
279
+ @statuses = @project2.statuses.paginate(:per_page => 2, :page => 1, :order => 'name asc')
280
+ end
281
+
282
+ should "return total pages" do
283
+ @statuses.total_pages.should == 2
284
+ end
285
+
286
+ should "return total entries" do
287
+ @statuses.total_entries.should == 3
288
+ end
289
+
290
+ should "return the subject" do
291
+ @statuses.collect(&:name).should == %w(Archived Complete)
292
+ end
293
+ end
294
+ end
295
+ end