mongoid 0.9.8 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
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