mongoid 0.9.8 → 0.9.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 (34) hide show
  1. data/README.textile +5 -4
  2. data/VERSION +1 -1
  3. data/lib/mongoid.rb +3 -28
  4. data/lib/mongoid/associations.rb +63 -44
  5. data/lib/mongoid/associations/{relates_to_one.rb → belongs_to_related.rb} +4 -4
  6. data/lib/mongoid/associations/has_many.rb +26 -12
  7. data/lib/mongoid/associations/has_many_related.rb +100 -0
  8. data/lib/mongoid/associations/has_one.rb +13 -2
  9. data/lib/mongoid/associations/{relates_to_many.rb → has_one_related.rb} +34 -9
  10. data/lib/mongoid/attributes.rb +108 -8
  11. data/lib/mongoid/commands.rb +3 -11
  12. data/lib/mongoid/commands/save.rb +2 -6
  13. data/lib/mongoid/document.rb +6 -70
  14. data/lib/mongoid/errors.rb +34 -0
  15. data/mongoid.gemspec +14 -11
  16. data/spec/integration/mongoid/associations_spec.rb +19 -14
  17. data/spec/spec_helper.rb +6 -3
  18. data/spec/unit/mongoid/associations/belongs_to_related_spec.rb +112 -0
  19. data/spec/unit/mongoid/associations/has_many_related_spec.rb +292 -0
  20. data/spec/unit/mongoid/associations/has_many_spec.rb +17 -0
  21. data/spec/unit/mongoid/associations/has_one_related_spec.rb +130 -0
  22. data/spec/unit/mongoid/associations/has_one_spec.rb +53 -0
  23. data/spec/unit/mongoid/associations_spec.rb +36 -8
  24. data/spec/unit/mongoid/attributes_spec.rb +218 -0
  25. data/spec/unit/mongoid/commands/save_spec.rb +4 -2
  26. data/spec/unit/mongoid/commands_spec.rb +4 -17
  27. data/spec/unit/mongoid/criteria_spec.rb +0 -5
  28. data/spec/unit/mongoid/document_spec.rb +26 -156
  29. data/spec/unit/mongoid/errors_spec.rb +87 -0
  30. metadata +14 -11
  31. data/lib/mongoid/commands/quick_save.rb +0 -19
  32. data/spec/unit/mongoid/associations/relates_to_many_spec.rb +0 -76
  33. data/spec/unit/mongoid/associations/relates_to_one_spec.rb +0 -112
  34. data/spec/unit/mongoid/commands/quick_save_spec.rb +0 -24
@@ -209,6 +209,23 @@ describe Mongoid::Associations::HasMany do
209
209
 
210
210
  end
211
211
 
212
+ describe "#nested_build" do
213
+
214
+ before do
215
+ @association = Mongoid::Associations::HasMany.new(
216
+ @document,
217
+ Mongoid::Associations::Options.new(:name => :addresses)
218
+ )
219
+ end
220
+
221
+ it "returns the newly built object in the association" do
222
+ @association.nested_build({ "0" => { :street => "Yet Another" } })
223
+ @association.size.should == 3
224
+ @association.last.street.should == "Yet Another"
225
+ end
226
+
227
+ end
228
+
212
229
  describe "#push" do
213
230
 
214
231
  before do
@@ -0,0 +1,130 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Associations::HasOneRelated do
4
+
5
+ let(:document) { stub(:id => "1") }
6
+ let(:options) { Mongoid::Associations::Options.new(:name => :game) }
7
+
8
+ describe "#build" do
9
+
10
+ before do
11
+ @parent = stub(:id => "5", :class => Person)
12
+ Game.expects(:first).returns(nil)
13
+ @association = Mongoid::Associations::HasOneRelated.new(@parent, options)
14
+ end
15
+
16
+ it "adds a new object to the association" do
17
+ @association.build(:score => 100)
18
+ @association.score.should == 100
19
+ end
20
+
21
+ it "sets the parent object id on the child" do
22
+ @association.build(:score => 100)
23
+ @association.person_id.should == @parent.id
24
+ end
25
+
26
+ end
27
+
28
+ describe "#create" do
29
+
30
+ before do
31
+ @parent = stub(:id => "5", :class => Person)
32
+ Game.expects(:first).returns(nil)
33
+ Mongoid::Commands::Save.expects(:execute)
34
+ @association = Mongoid::Associations::HasOneRelated.new(@parent, options)
35
+ end
36
+
37
+ it "adds a new object to the association" do
38
+ @association.create(:score => 100)
39
+ @association.score.should == 100
40
+ end
41
+
42
+ it "sets the parent object id on the child" do
43
+ @association.create(:score => 100)
44
+ @association.person_id.should == @parent.id
45
+ end
46
+
47
+ end
48
+
49
+ describe ".initialize" do
50
+
51
+ before do
52
+ @person = Person.new
53
+ @game = stub
54
+ end
55
+
56
+ it "finds the association game by the parent key" do
57
+ Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(@game)
58
+ @person.game.should == @game
59
+ end
60
+
61
+ end
62
+
63
+ describe ".instantiate" do
64
+
65
+ it "delegates to new" do
66
+ Mongoid::Associations::HasOneRelated.expects(:new).with(document, options)
67
+ Mongoid::Associations::HasOneRelated.instantiate(document, options)
68
+ end
69
+
70
+ end
71
+
72
+ describe "#method_missing" do
73
+
74
+ before do
75
+ @person = Person.new
76
+ @game = stub
77
+ end
78
+
79
+ it "delegates to the documet" do
80
+ Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(@game)
81
+ @game.expects(:strange_method)
82
+ association = Mongoid::Associations::HasOneRelated.instantiate(@person, options)
83
+ association.strange_method
84
+ end
85
+
86
+ end
87
+
88
+ describe ".macro" do
89
+
90
+ it "returns :has_one_related" do
91
+ Mongoid::Associations::HasOneRelated.macro.should == :has_one_related
92
+ end
93
+
94
+ end
95
+
96
+ describe "#nil?" do
97
+
98
+ before do
99
+ @person = Person.new
100
+ @game = stub
101
+ Game.expects(:first).with(:conditions => { "person_id"=> @person.id }).returns(nil)
102
+ end
103
+
104
+ it "delegates to the document" do
105
+ association = Mongoid::Associations::HasOneRelated.instantiate(@person, options)
106
+ association.should be_nil
107
+ end
108
+
109
+ end
110
+
111
+ describe ".update" do
112
+
113
+ before do
114
+ @person = Person.new
115
+ @game = stub
116
+ end
117
+
118
+ it "sets the parent on the child association" do
119
+ @game.expects(:person=).with(@person)
120
+ Mongoid::Associations::HasOneRelated.update(@game, @person, options)
121
+ end
122
+
123
+ it "returns the child" do
124
+ @game.expects(:person=).with(@person)
125
+ Mongoid::Associations::HasOneRelated.update(@game, @person, options).should == @game
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -80,6 +80,27 @@ describe Mongoid::Associations::HasOne do
80
80
 
81
81
  end
82
82
 
83
+ describe "#nested_build" do
84
+
85
+ context "when attributes provided" do
86
+
87
+ before do
88
+ @association = Mongoid::Associations::HasOne.new(
89
+ @document,
90
+ @attributes[:mixed_drink],
91
+ Mongoid::Associations::Options.new(:name => :mixed_drink)
92
+ )
93
+ end
94
+
95
+ it "replaces the existing has_one" do
96
+ drink = @association.nested_build({ :name => "Sapphire and Tonic" })
97
+ drink.name.should == "Sapphire and Tonic"
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+
83
104
  describe ".instantiate" do
84
105
 
85
106
  context "when attributes exist" do
@@ -129,4 +150,36 @@ describe Mongoid::Associations::HasOne do
129
150
 
130
151
  end
131
152
 
153
+ describe "#valid?" do
154
+
155
+ context "when the document is nil" do
156
+
157
+ before do
158
+ @document = stub(:attributes => {})
159
+ @options = Mongoid::Associations::Options.new(:name => :name)
160
+ @association = Mongoid::Associations::HasOne.instantiate(@document, @options)
161
+ end
162
+
163
+ it "returns false" do
164
+ @association.valid?.should be_false
165
+ end
166
+
167
+ end
168
+
169
+ context "when the document is not nil" do
170
+
171
+ before do
172
+ @document = stub(:attributes => { :name => { :first_name => "Test" } }, :update => true)
173
+ @options = Mongoid::Associations::Options.new(:name => :name)
174
+ @association = Mongoid::Associations::HasOne.instantiate(@document, @options)
175
+ end
176
+
177
+ it "validates the document" do
178
+ @association.valid?.should be_true
179
+ end
180
+
181
+ end
182
+
183
+ end
184
+
132
185
  end
@@ -97,6 +97,14 @@ describe Mongoid::Associations do
97
97
  code.phone_number.should == phone_number
98
98
  end
99
99
 
100
+ context "when inverse_of not supplied" do
101
+
102
+ it "raises an error" do
103
+ lambda { Person.class_eval { belongs_to :nothing } }.should raise_error
104
+ end
105
+
106
+ end
107
+
100
108
  context "when navigating the graph" do
101
109
 
102
110
  before do
@@ -241,20 +249,39 @@ describe Mongoid::Associations do
241
249
 
242
250
  end
243
251
 
244
- describe ".relates_to_one" do
252
+ describe ".belongs_to_related" do
253
+
254
+ before do
255
+ @game = Game.new
256
+ end
245
257
 
246
258
  it "creates an id field for the relationship" do
247
- Person.new.should respond_to(:game_id)
259
+ @game.should respond_to(:person_id)
248
260
  end
249
261
 
250
- it "creates a getter and setter for the relationship" do
251
- Person.new.should respond_to(:game)
252
- Person.new.should respond_to(:game=)
262
+ it "creates a getter for the parent" do
263
+ @game.should respond_to(:person)
264
+ end
265
+
266
+ end
267
+
268
+ describe ".has_one_related" do
269
+
270
+ before do
271
+ @person = Person.new
272
+ end
273
+
274
+ it "creates a getter for the relationship" do
275
+ @person.should respond_to(:game)
276
+ end
277
+
278
+ it "creates a setter for the relationship" do
279
+ @person.should respond_to(:game=)
253
280
  end
254
281
 
255
282
  end
256
283
 
257
- describe ".relates_to_many" do
284
+ describe ".has_many_related" do
258
285
 
259
286
  it "creates a getter and setter for the relationship" do
260
287
  Person.new.should respond_to(:posts)
@@ -274,7 +301,7 @@ describe Mongoid::Associations do
274
301
  end
275
302
 
276
303
  it "saves each association" do
277
- @related.expects(:quick_save).returns(@related)
304
+ @related.expects(:save).returns(@related)
278
305
  @person.update_associations(:posts)
279
306
  end
280
307
 
@@ -287,6 +314,7 @@ describe Mongoid::Associations do
287
314
  end
288
315
 
289
316
  it "does nothing" do
317
+ Post.expects(:find).returns([])
290
318
  @person.update_associations(:posts)
291
319
  @person.posts.first.should be_nil
292
320
  end
@@ -306,7 +334,7 @@ describe Mongoid::Associations do
306
334
  end
307
335
 
308
336
  it "saves each association" do
309
- @related.expects(:quick_save).returns(@related)
337
+ @related.expects(:save).returns(@related)
310
338
  @person.update_association(:game)
311
339
  end
312
340
 
@@ -2,6 +2,78 @@ require "spec_helper"
2
2
 
3
3
  describe Mongoid::Attributes do
4
4
 
5
+ describe ".accepts_nested_attributes_for" do
6
+
7
+ before do
8
+ @person = Person.new
9
+ end
10
+
11
+ it "adds a setter for the association attributes" do
12
+ @person.should respond_to(:addresses_attributes=)
13
+ end
14
+
15
+ describe "#association_attributes=" do
16
+
17
+ context "on a has many association" do
18
+
19
+ context "when association is empty" do
20
+
21
+ before do
22
+ @attributes = {
23
+ "0" => { "street" => "Folsom", "city" => "San Francisco" }
24
+ }
25
+ @person.addresses_attributes = @attributes
26
+ end
27
+
28
+ it "adds a new document to the association" do
29
+ address = @person.addresses.first
30
+ address.street.should == "Folsom"
31
+ address.city.should == "San Francisco"
32
+ end
33
+
34
+ end
35
+
36
+ context "when association is not empty" do
37
+
38
+ before do
39
+ @person = Person.new
40
+ @person.addresses.build(:street => "Broadway", :city => "New York")
41
+ @attributes = {
42
+ "0" => { "street" => "Folsom", "city" => "San Francisco" }
43
+ }
44
+ @person.addresses_attributes = @attributes
45
+ end
46
+
47
+ it "updates the existing attributes on the association" do
48
+ @person.addresses.size.should == 2
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ context "on a has one association" do
56
+
57
+ before do
58
+ @person = Person.new
59
+ @attributes = {
60
+ "first_name" => "Fernando", "last_name" => "Torres"
61
+ }
62
+ @person.name_attributes = @attributes
63
+ end
64
+
65
+ it "replaces the document on the association" do
66
+ name = @person.name
67
+ name.first_name.should == "Fernando"
68
+ name.last_name.should == "Torres"
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
76
+
5
77
  describe "#process" do
6
78
 
7
79
  context "when supplied hash has values" do
@@ -94,4 +166,150 @@ describe Mongoid::Attributes do
94
166
 
95
167
  end
96
168
 
169
+ describe "#read_attribute" do
170
+
171
+ context "when attribute does not exist" do
172
+
173
+ before do
174
+ @person = Person.new
175
+ end
176
+
177
+ it "returns the default value" do
178
+ @person.age.should == 100
179
+ end
180
+
181
+ end
182
+
183
+ end
184
+
185
+ describe "#remove_attribute" do
186
+
187
+ context "when the attribute exists" do
188
+
189
+ it "removes the attribute" do
190
+ person = Person.new(:title => "Sir")
191
+ person.remove_attribute(:title)
192
+ person.title.should be_nil
193
+ end
194
+
195
+ end
196
+
197
+ context "when the attribute does not exist" do
198
+
199
+ it "does nothing" do
200
+ person = Person.new
201
+ person.remove_attribute(:title)
202
+ person.title.should be_nil
203
+ end
204
+
205
+ end
206
+
207
+ end
208
+
209
+ describe "#write_attribute" do
210
+
211
+ context "when attribute does not exist" do
212
+
213
+ before do
214
+ @person = Person.new
215
+ end
216
+
217
+ it "returns the default value" do
218
+ @person.age = nil
219
+ @person.age.should == 100
220
+ end
221
+
222
+ end
223
+
224
+ context "when field has a default value" do
225
+
226
+ before do
227
+ @person = Person.new
228
+ end
229
+
230
+ it "should allow overwriting of the default value" do
231
+ @person.terms = true
232
+ @person.terms.should be_true
233
+ end
234
+
235
+ end
236
+
237
+ end
238
+
239
+ describe "#write_attributes" do
240
+
241
+ context "typecasting" do
242
+
243
+ before do
244
+ @person = Person.new
245
+ @attributes = { :age => "50" }
246
+ end
247
+
248
+ it "properly casts values" do
249
+ @person.write_attributes(@attributes)
250
+ @person.age.should == 50
251
+ end
252
+
253
+ end
254
+
255
+ context "on a parent document" do
256
+
257
+ context "when the parent has a has many through a has one" do
258
+
259
+ before do
260
+ @owner = PetOwner.new(:title => "Mr")
261
+ @pet = Pet.new(:name => "Fido")
262
+ @owner.pet = @pet
263
+ @vet_visit = VetVisit.new(:date => Date.today)
264
+ @pet.vet_visits = [@vet_visit]
265
+ end
266
+
267
+ it "does not overwrite child attributes if not in the hash" do
268
+ @owner.write_attributes({ :pet => { :name => "Bingo" } })
269
+ @owner.pet.name.should == "Bingo"
270
+ @owner.pet.vet_visits.size.should == 1
271
+ end
272
+
273
+ end
274
+
275
+ end
276
+
277
+ context "on a child document" do
278
+
279
+ context "when child is part of a has one" do
280
+
281
+ before do
282
+ @person = Person.new(:title => "Sir", :age => 30)
283
+ @name = Name.new(:first_name => "Test", :last_name => "User")
284
+ @person.name = @name
285
+ end
286
+
287
+ it "sets the child attributes on the parent" do
288
+ @name.write_attributes(:first_name => "Test2", :last_name => "User2")
289
+ @person.attributes[:name].should ==
290
+ { "_id" => "test-user", "first_name" => "Test2", "last_name" => "User2" }
291
+ end
292
+
293
+ end
294
+
295
+ context "when child is part of a has many" do
296
+
297
+ before do
298
+ @person = Person.new(:title => "Sir")
299
+ @address = Address.new(:street => "Test")
300
+ @person.addresses << @address
301
+ end
302
+
303
+ it "updates the child attributes on the parent" do
304
+ @address.write_attributes("street" => "Test2")
305
+ @person.attributes[:addresses].should ==
306
+ [ { "_id" => "test", "street" => "Test2" } ]
307
+ end
308
+
309
+ end
310
+
311
+ end
312
+
313
+ end
314
+
97
315
  end