couchobject 0.5.0 → 0.6.0
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.
- data/History.txt +10 -0
- data/Manifest.txt +30 -6
- data/README.txt +580 -42
- data/TODO +2 -2
- data/config/hoe.rb +1 -1
- data/lib/couch_object.rb +7 -2
- data/lib/couch_object/database.rb +19 -34
- data/lib/couch_object/document.rb +13 -6
- data/lib/couch_object/error_classes.rb +110 -0
- data/lib/couch_object/persistable.rb +954 -36
- data/lib/couch_object/persistable/has_many_relations_array.rb +91 -0
- data/lib/couch_object/persistable/meta_classes.rb +568 -0
- data/lib/couch_object/persistable/overloaded_methods.rb +209 -0
- data/lib/couch_object/server.rb +1 -1
- data/lib/couch_object/utils.rb +44 -0
- data/lib/couch_object/version.rb +1 -1
- data/lib/couch_object/view.rb +129 -6
- data/script/console +0 -0
- data/script/destroy +0 -0
- data/script/generate +0 -0
- data/script/txt2html +0 -0
- data/spec/database_spec.rb +23 -31
- data/spec/database_spec.rb.orig +173 -0
- data/spec/document_spec.rb +21 -3
- data/spec/integration/database_integration_spec.rb +46 -15
- data/spec/integration/integration_helper.rb +3 -3
- data/spec/persistable/callback.rb +44 -0
- data/spec/persistable/callback_spec.rb +44 -0
- data/spec/persistable/cloning.rb +77 -0
- data/spec/persistable/cloning_spec.rb +77 -0
- data/spec/persistable/comparing_objects.rb +350 -0
- data/spec/persistable/comparing_objects_spec.rb +350 -0
- data/spec/persistable/deleting.rb +113 -0
- data/spec/persistable/deleting_spec.rb +113 -0
- data/spec/persistable/error_messages.rb +32 -0
- data/spec/persistable/error_messages_spec.rb +32 -0
- data/spec/persistable/loading.rb +339 -0
- data/spec/persistable/loading_spec.rb +339 -0
- data/spec/persistable/new_methods.rb +70 -0
- data/spec/persistable/new_methods_spec.rb +70 -0
- data/spec/persistable/persistable_helper.rb +194 -0
- data/spec/persistable/relations.rb +470 -0
- data/spec/persistable/relations_spec.rb +470 -0
- data/spec/persistable/saving.rb +137 -0
- data/spec/persistable/saving_spec.rb +137 -0
- data/spec/persistable/setting_storage_location.rb +65 -0
- data/spec/persistable/setting_storage_location_spec.rb +65 -0
- data/spec/persistable/timestamps.rb +76 -0
- data/spec/persistable/timestamps_spec.rb +76 -0
- data/spec/persistable/unsaved_changes.rb +211 -0
- data/spec/persistable/unsaved_changes_spec.rb +211 -0
- data/spec/server_spec.rb +5 -5
- data/spec/utils_spec.rb +60 -0
- data/spec/view_spec.rb +40 -7
- data/website/index.html +22 -7
- data/website/index.txt +13 -5
- metadata +93 -61
- data/bin/couch_ruby_view_requestor +0 -81
- data/lib/couch_object/model.rb +0 -5
- data/lib/couch_object/proc_condition.rb +0 -14
- data/spec/model_spec.rb +0 -5
- data/spec/persistable_spec.rb +0 -91
- data/spec/proc_condition_spec.rb +0 -26
@@ -0,0 +1,470 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/persistable_helper.rb'
|
2
|
+
|
3
|
+
describe CouchObject::Persistable, "methods added and their values: " do
|
4
|
+
before(:each) do
|
5
|
+
@building = ApartmentBuilding.new
|
6
|
+
@inhabitant = Inhabitant.new
|
7
|
+
@apartment = Apartment.new
|
8
|
+
|
9
|
+
@building.stub!(:couch_load_has_many_relations).
|
10
|
+
and_return(CouchObject::Persistable::HasManyRelation.new(@building))
|
11
|
+
@inhabitant.stub!(:couch_load_has_many_relations).
|
12
|
+
and_return(CouchObject::Persistable::HasManyRelation.new(@inhabitant))
|
13
|
+
@apartment.stub!(:couch_load_has_many_relations).
|
14
|
+
and_return(CouchObject::Persistable::HasManyRelation.new(@apartment))
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should give ApartmentBuilding inhabitant getters and setters" do
|
18
|
+
@building.respond_to?(:inhabitants).should == true
|
19
|
+
@building.respond_to?(:apartments).should == true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should give Inhabitant apartment_building getters and setters" do
|
23
|
+
@inhabitant.respond_to?(:apartment_building).should == true
|
24
|
+
@inhabitant.respond_to?(:apartment_building=).should == true
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should give Apartment apartment_building getters and setters" do
|
28
|
+
@apartment.respond_to?(:apartment_building).should == true
|
29
|
+
@apartment.respond_to?(:apartment_building=).should == true
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should be able to list the classes it has relations to" do
|
33
|
+
@building.respond_to?(:has_many).should == true
|
34
|
+
@building.respond_to?(:belongs_to).should == true
|
35
|
+
@apartment.respond_to?(:has_many).should == true
|
36
|
+
@apartment.respond_to?(:belongs_to).should == true
|
37
|
+
@inhabitant.respond_to?(:has_many).should == true
|
38
|
+
@inhabitant.respond_to?(:belongs_to).should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should be able to list as what it has belongs_to relations" do
|
42
|
+
@apartment.belongs_to.each do |what_it_belongs_to|
|
43
|
+
@apartment.respond_to?("belongs_to_#{what_it_belongs_to}_as".to_sym).
|
44
|
+
should == true
|
45
|
+
@apartment.send("belongs_to_#{what_it_belongs_to}_as".to_sym).
|
46
|
+
should == :apartments
|
47
|
+
end
|
48
|
+
@inhabitant.belongs_to.each do |what_it_belongs_to|
|
49
|
+
@inhabitant.respond_to?("belongs_to_#{what_it_belongs_to}_as".to_sym).
|
50
|
+
should == true
|
51
|
+
@inhabitant.send("belongs_to_#{what_it_belongs_to}_as".to_sym).
|
52
|
+
should == :inhabitants
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should list the has_many relations as an array" do
|
57
|
+
@building.has_many.should be_a_kind_of(Array)
|
58
|
+
@apartment.has_many.should be_a_kind_of(Array)
|
59
|
+
@inhabitant.has_many.should be_a_kind_of(Array)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should list the belongs_to relation as a symbol or nil" do
|
63
|
+
@inhabitant.belongs_to.should be_a_kind_of(Array)
|
64
|
+
@apartment.belongs_to.should be_a_kind_of(Array)
|
65
|
+
@building.belongs_to.should == []
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should be able to return the names of the accessor methods used to access its relations" do
|
69
|
+
|
70
|
+
@building.has_many.should == [:inhabitants, :apartments]
|
71
|
+
@inhabitant.belongs_to.should == [:apartment_building]
|
72
|
+
@apartment.belongs_to.should == [:apartment_building]
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe CouchObject::Persistable, "getting and setting relations: " do
|
78
|
+
before(:each) do
|
79
|
+
@building_1 = ApartmentBuilding.new
|
80
|
+
@building_2 = ApartmentBuilding.new
|
81
|
+
@inhabitant_1 = Inhabitant.new
|
82
|
+
@inhabitant_2 = Inhabitant.new
|
83
|
+
@apartment = Apartment.new
|
84
|
+
|
85
|
+
@db = mock("mock db")
|
86
|
+
# Should call the DB at all...
|
87
|
+
CouchObject::Database.should_receive(:open).exactly(0).and_return(@db)
|
88
|
+
|
89
|
+
@building_1.stub!(:couch_load_has_many_relations).and_return(CouchObject::Persistable::HasManyRelation.new(@building_1))
|
90
|
+
@building_2.stub!(:couch_load_has_many_relations).and_return(CouchObject::Persistable::HasManyRelation.new(@building_2))
|
91
|
+
@inhabitant_1.stub!(:couch_load_has_many_relations).and_return(CouchObject::Persistable::HasManyRelation.new(@inhabitant_1))
|
92
|
+
@inhabitant_2.stub!(:couch_load_has_many_relations).and_return(CouchObject::Persistable::HasManyRelation.new(@inhabitant_2))
|
93
|
+
@apartment.stub!(:couch_load_has_many_relations).and_return(CouchObject::Persistable::HasManyRelation.new(@apartment))
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should return an empty array for empty has_many relatoins" do
|
97
|
+
@building_1.inhabitants.should be_a_kind_of(Array)
|
98
|
+
@building_1.inhabitants.should == []
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should return nil for empty belongs_to relatoins" do
|
102
|
+
@inhabitant_1.apartment_building.should == nil
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should be able to add any number of object to a has_many relation and get them again" do
|
106
|
+
@building_1.inhabitants.should == []
|
107
|
+
@building_1.inhabitants << @inhabitant_1 << @inhabitant_2
|
108
|
+
# @building_1.inhabitants.size.should == 2
|
109
|
+
# @building_1.inhabitants.should == [@inhabitant_1, @inhabitant_2]
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should be able to assign a class that it belongs to and retrieve it" do
|
113
|
+
@inhabitant_1.apartment_building = @building_1
|
114
|
+
@inhabitant_1.apartment_building.should == @building_1
|
115
|
+
@inhabitant_1.apartment_building = @building_2
|
116
|
+
@inhabitant_1.apartment_building.should_not == @building_1
|
117
|
+
end
|
118
|
+
|
119
|
+
it "when setting a has_many relationsship, the related class should be updated so it has a belongs_to relationsship with the other class" do
|
120
|
+
@building_1.inhabitants << @inhabitant_1
|
121
|
+
@inhabitant_1.apartment_building.should == @building_1
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should be able to remove an object from a has_many relationsship" do
|
125
|
+
@building_1.inhabitants << @inhabitant_1
|
126
|
+
@building_1.inhabitants.size.should == 1
|
127
|
+
@building_1.inhabitants.remove(@inhabitant_1)
|
128
|
+
@building_1.inhabitants.size.should == 0
|
129
|
+
@inhabitant_1.apartment_building.should == nil
|
130
|
+
end
|
131
|
+
|
132
|
+
it "when setting a belongs_to relationsship, the related class should be updated so it has a has_many relationsship to the other class" do
|
133
|
+
@inhabitant_1.apartment_building = @building_1
|
134
|
+
@building_1.inhabitants.size.should == 1
|
135
|
+
@building_1.inhabitants.first.should == @inhabitant_1
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should be able to set a belongs_to relationship to a master that already has children" do
|
139
|
+
@building_1.inhabitants << @inhabitant_1
|
140
|
+
@building_1.inhabitants.size.should == 1
|
141
|
+
@inhabitant_2.apartment_building = @building_1
|
142
|
+
@building_1.inhabitants.size.should == 2
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
describe CouchObject::Persistable, "errors when creating classes with bad relations :)" do
|
148
|
+
it "should raise an error for badly formatted belongs_to relations" do
|
149
|
+
lambda {
|
150
|
+
class Garage
|
151
|
+
include CouchObject::Persistable
|
152
|
+
belongs_to :apartment_building # missing , :as => :something
|
153
|
+
end
|
154
|
+
}.should raise_error(CouchObject::Errors::BelongsToAssociationError)
|
155
|
+
|
156
|
+
lambda {
|
157
|
+
class Lamp
|
158
|
+
include CouchObject::Persistable
|
159
|
+
belongs_to # missing :apartment_building, :as => :something
|
160
|
+
end
|
161
|
+
}.should raise_error(CouchObject::Errors::BelongsToAssociationError)
|
162
|
+
|
163
|
+
lambda {
|
164
|
+
class Mouse
|
165
|
+
include CouchObject::Persistable
|
166
|
+
belongs_to :apartment_building, :as => :animal # is correct
|
167
|
+
end
|
168
|
+
}.should_not \
|
169
|
+
raise_error(CouchObject::Errors::BelongsToAssociationError)
|
170
|
+
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
it "should raise an error for badly formatted has_many relations" do
|
175
|
+
lambda {
|
176
|
+
class Oven
|
177
|
+
include CouchObject::Persistable
|
178
|
+
has_many # missing what it is related to :users
|
179
|
+
end
|
180
|
+
}.should raise_error(CouchObject::Errors::HasManyAssociationError)
|
181
|
+
|
182
|
+
lambda {
|
183
|
+
class FavoriteOven
|
184
|
+
include CouchObject::Persistable
|
185
|
+
has_many :users
|
186
|
+
end
|
187
|
+
}.should_not \
|
188
|
+
raise_error(CouchObject::Errors::HasManyAssociationError)
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
describe CouchObject::Persistable, "saving related objects: " do
|
195
|
+
before(:each) do
|
196
|
+
@building = ApartmentBuilding.new
|
197
|
+
@apartment = Apartment.new
|
198
|
+
|
199
|
+
@db = mock("mock db")
|
200
|
+
|
201
|
+
content = HTTPResponse.new(JSON.unparse({
|
202
|
+
"_id" => "123BAC",
|
203
|
+
"_rev" => "946B7D1C",
|
204
|
+
}))
|
205
|
+
|
206
|
+
@document_response = CouchObject::Response.new(content)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "a class should save it's has_many relations" do
|
210
|
+
CouchObject::Database.should_receive(:open).exactly(3).and_return(@db)
|
211
|
+
@db.should_receive(:post).exactly(3).and_return(@document_response)
|
212
|
+
|
213
|
+
another_apartment = @apartment.clone
|
214
|
+
|
215
|
+
@apartment.new?.should == true
|
216
|
+
another_apartment.new?.should == true
|
217
|
+
@building.new?.should == true
|
218
|
+
|
219
|
+
# Should not load the relations because it is a new object
|
220
|
+
@building.apartments.class.should == \
|
221
|
+
CouchObject::Persistable::HasManyRelation
|
222
|
+
|
223
|
+
@building.apartments << @apartment << another_apartment
|
224
|
+
@building.apartments.size.should == 2
|
225
|
+
|
226
|
+
@building.inhabitants.class.should == \
|
227
|
+
CouchObject::Persistable::HasManyRelation
|
228
|
+
|
229
|
+
@building.inhabitants.size.should == 0
|
230
|
+
|
231
|
+
@apartment.new?.should == true
|
232
|
+
another_apartment.new?.should == true
|
233
|
+
@building.new?.should == true
|
234
|
+
|
235
|
+
# Should call save on itself which results in a post, and
|
236
|
+
# then on its children which also results in a post.
|
237
|
+
# And also load it's inhabitants relations
|
238
|
+
@building.save
|
239
|
+
|
240
|
+
@apartment.new?.should == false
|
241
|
+
another_apartment.new?.should == false
|
242
|
+
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should save its belongs_to relation if it is unsaved" do
|
246
|
+
CouchObject::Database.should_receive(:open).exactly(2).and_return(@db)
|
247
|
+
@db.should_receive(:post).exactly(2).and_return(@document_response)
|
248
|
+
|
249
|
+
@building.new?.should == true
|
250
|
+
@apartment.new?.should == true
|
251
|
+
@building.apartments << @apartment
|
252
|
+
|
253
|
+
@apartment.save("foo")
|
254
|
+
|
255
|
+
@apartment.new?.should == false
|
256
|
+
@building.new?.should == false
|
257
|
+
|
258
|
+
@building.id.should_not == nil
|
259
|
+
@apartment.id.should_not == nil
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
it "a class that normally is in a belongs_to relation but doesn't have a relation set should be able to save" do
|
264
|
+
CouchObject::Database.should_receive(:open).exactly(1).and_return(@db)
|
265
|
+
@db.should_receive(:post).exactly(1).and_return(@document_response)
|
266
|
+
|
267
|
+
@apartment.new?.should == true
|
268
|
+
@apartment.save("foo")
|
269
|
+
@apartment.new?.should == false
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should not load the belongs_to relations if they are not already loaded before saving" do
|
273
|
+
@inhabitant_content = %{ {"_id":"50F1A07A283C1879057AFE4C4B727D35","_rev":"1957693345","belongs_to":{"inhabitants":"12A64B5156002BFD66F23F559C5AD5FA"},"class":"Inhabitant","attributes":{}}
|
274
|
+
}
|
275
|
+
|
276
|
+
response = HTTPResponse.new(@inhabitant_content)
|
277
|
+
|
278
|
+
CouchObject::Database.should_receive(:open).exactly(1).and_return(@db)
|
279
|
+
|
280
|
+
@db.should_receive(:get).once.with("foo").and_return(response)
|
281
|
+
|
282
|
+
inhabitant = Inhabitant.get_with_smart_save("foo")
|
283
|
+
inhabitant.location.should_not == nil
|
284
|
+
|
285
|
+
# Telling the object not to load its relatives
|
286
|
+
inhabitant.save
|
287
|
+
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
describe CouchObject::Persistable, "loading object relations: " do
|
292
|
+
before(:each) do
|
293
|
+
@db = mock("mock db")
|
294
|
+
|
295
|
+
@view_content_no_rows = %{
|
296
|
+
{"total_rows":3,"rows":[]}
|
297
|
+
}
|
298
|
+
|
299
|
+
@apartment_building_content = %{ {"_id":"A26EDC59D99D50C2CB2615404D357E49","_rev":"1756574922","class":"ApartmentBuilding","attributes":{}}
|
300
|
+
}
|
301
|
+
|
302
|
+
@inhabitant_content = %{ {"_id":"50F1A07A283C1879057AFE4C4B727D35","_rev":"1957693345","belongs_to":{"inhabitants":"12A64B5156002BFD66F23F559C5AD5FA"},"class":"Inhabitant","attributes":{}}
|
303
|
+
}
|
304
|
+
|
305
|
+
@inhabitant_content_from_view = %{
|
306
|
+
{"total_rows":2,"offset":0,"rows":[{"id":"50F1A07A283C1879057AFE4C4B727D35","key":["12A64B5156002BFD66F23F559C5AD5FA","inhabitants"],"value":{"_id":"50F1A07A283C1879057AFE4C4B727D35","_rev":"1957693345","class":"Inhabitant","attributes":{},"belongs_to":{"inhabitants":"12A64B5156002BFD66F23F559C5AD5FA"}}}]}
|
307
|
+
}
|
308
|
+
|
309
|
+
@apartment_building_inhabitants = %{
|
310
|
+
{"total_rows":2,"offset":0,"rows":[{"id":"241757E4D7D2272C78048B4007399837","key":["12A64B5156002BFD66F23F559C5AD5FA","inhabitants"],"value":{"_id":"241757E4D7D2272C78048B4007399837","_rev":"2508041460","class":"Inhabitant","attributes":{},"belongs_to":{"inhabitants":"CCC19E6CAE557D058CC8E0961507AC4C"}}},{"id":"E94C93DEDB94BFC30B9AB396D4874D52","key":["12A64B5156002BFD66F23F559C5AD5FA","inhabitants"],"value":{"_id":"E94C93DEDB94BFC30B9AB396D4874D52","_rev":"960098874","class":"Inhabitant","attributes":{},"belongs_to":{"inhabitants":"CCC19E6CAE557D058CC8E0961507AC4C"}}}]}
|
311
|
+
}
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should load all has_many relations when needed" do
|
316
|
+
response = HTTPResponse.new(@apartment_building_content)
|
317
|
+
response_relation = HTTPResponse.new(@apartment_building_inhabitants)
|
318
|
+
|
319
|
+
CouchObject::Database.should_receive(:open).exactly(2).and_return(@db)
|
320
|
+
|
321
|
+
@db.should_receive(:get).with("foo").and_return(response)
|
322
|
+
|
323
|
+
# has_many relations are loaded
|
324
|
+
@db.should_receive(:get).
|
325
|
+
with("_view/couch_object_has_many_relations/related_documents?" + \
|
326
|
+
"key=[%22A26EDC59D99D50C2CB2615404D357E49%22,%22inhabitants%22]").
|
327
|
+
and_return(response_relation)
|
328
|
+
|
329
|
+
apartment_building = ApartmentBuilding.get_by_id("foo")
|
330
|
+
apartment_building.location.should_not == nil
|
331
|
+
|
332
|
+
# The content should be loaded on first request!
|
333
|
+
apartment_building.inhabitants.size.should == 2
|
334
|
+
|
335
|
+
end
|
336
|
+
|
337
|
+
it "should load belongs_to relations when needed" do
|
338
|
+
response_inhabitant = HTTPResponse.new(@inhabitant_content)
|
339
|
+
response_inhabitant_from_view = HTTPResponse.
|
340
|
+
new(@inhabitant_content_from_view)
|
341
|
+
response_apartment_buil = HTTPResponse.new(@apartment_building_content)
|
342
|
+
|
343
|
+
# 1. class gets loaded
|
344
|
+
# 2. belongs_to relation is loaded
|
345
|
+
# 3. then self is added to the belongs_to relations has_many relation
|
346
|
+
# which is first loaded from the DB
|
347
|
+
# 4. ? I don't know where it gets called...
|
348
|
+
CouchObject::Database.should_receive(:open).exactly(4).and_return(@db)
|
349
|
+
|
350
|
+
@db.should_receive(:get).with("foo").once.and_return(response_inhabitant)
|
351
|
+
@db.should_receive(:get).once.
|
352
|
+
with("12A64B5156002BFD66F23F559C5AD5FA").
|
353
|
+
and_return(response_apartment_buil)
|
354
|
+
@db.should_receive(:get).once.with("_view/couch_object_has_many_relat" + \
|
355
|
+
"ions/related_documents?key=[%22A26EDC59D99D50C2CB2615404D357E49" + \
|
356
|
+
"%22,%22inhabitants%22]").and_return(response_inhabitant_from_view)
|
357
|
+
|
358
|
+
# 1)
|
359
|
+
inhabitant = Inhabitant.get_by_id("foo","foo_db")
|
360
|
+
inhabitant.new?.should == false
|
361
|
+
|
362
|
+
# 2)
|
363
|
+
# 3)
|
364
|
+
inhabitant.apartment_building.class.should == ApartmentBuilding
|
365
|
+
inhabitant.apartment_building.new?.should == false
|
366
|
+
inhabitant.apartment_building.inhabitants.first.should == inhabitant
|
367
|
+
|
368
|
+
end
|
369
|
+
|
370
|
+
it "should be possible to tell the object not to load its has many relations" do
|
371
|
+
response = HTTPResponse.new(@apartment_building_content)
|
372
|
+
|
373
|
+
CouchObject::Database.should_receive(:open).exactly(1).and_return(@db)
|
374
|
+
|
375
|
+
@db.should_receive(:get).with("foo").and_return(response)
|
376
|
+
|
377
|
+
apartment_building = ApartmentBuilding.get_by_id("foo")
|
378
|
+
apartment_building.location.should_not == nil
|
379
|
+
|
380
|
+
# Telling the object not to load its relatives
|
381
|
+
apartment_building.do_not_load_has_many_relations
|
382
|
+
|
383
|
+
# The content should be loaded on first request!
|
384
|
+
apartment_building.inhabitants.size.should == 0
|
385
|
+
|
386
|
+
end
|
387
|
+
|
388
|
+
it "should be possible to tell the object not to load its has many relations" do
|
389
|
+
response = HTTPResponse.new(@inhabitant_content)
|
390
|
+
|
391
|
+
CouchObject::Database.should_receive(:open).exactly(1).and_return(@db)
|
392
|
+
|
393
|
+
@db.should_receive(:get).once.with("foo").and_return(response)
|
394
|
+
|
395
|
+
inhabitant = Inhabitant.get("foo")
|
396
|
+
inhabitant.location.should_not == nil
|
397
|
+
|
398
|
+
# Telling the object not to load its relatives
|
399
|
+
inhabitant.do_not_load_belongs_to_relations
|
400
|
+
|
401
|
+
# The content should be loaded on first request!
|
402
|
+
inhabitant.apartment_building.should == nil
|
403
|
+
|
404
|
+
end
|
405
|
+
|
406
|
+
end
|
407
|
+
|
408
|
+
describe CouchObject::Persistable, "has_one relations" do
|
409
|
+
before(:each) do
|
410
|
+
@person = Person.new
|
411
|
+
@life = Life.new
|
412
|
+
|
413
|
+
@db = mock("mock db")
|
414
|
+
|
415
|
+
content = HTTPResponse.new(JSON.unparse({
|
416
|
+
"_id" => "123BAC",
|
417
|
+
"_rev" => "946B7D1C",
|
418
|
+
}))
|
419
|
+
|
420
|
+
@document_response = CouchObject::Response.new(content)
|
421
|
+
end
|
422
|
+
|
423
|
+
it "should be able to set a has_one relation" do
|
424
|
+
@person.life = @life
|
425
|
+
@life.person.should == @person
|
426
|
+
|
427
|
+
@person.life = nil
|
428
|
+
@life.person.should == nil
|
429
|
+
|
430
|
+
@life.person = @person
|
431
|
+
@person.life.should == @life
|
432
|
+
end
|
433
|
+
|
434
|
+
it "should be able to save its has_one relation" do
|
435
|
+
CouchObject::Database.should_receive(:open).exactly(2).and_return(@db)
|
436
|
+
@db.should_receive(:post).exactly(2).and_return(@document_response)
|
437
|
+
@person.life = @life
|
438
|
+
@person.save
|
439
|
+
@person.new?.should == false
|
440
|
+
@life.new?.should == false
|
441
|
+
end
|
442
|
+
|
443
|
+
it "the child should save it's has_one parent when it is a new object" do
|
444
|
+
CouchObject::Database.should_receive(:open).exactly(2).and_return(@db)
|
445
|
+
@db.should_receive(:post).exactly(2).and_return(@document_response)
|
446
|
+
@person.life = @life
|
447
|
+
@life.save
|
448
|
+
@person.new?.should == false
|
449
|
+
@life.new?.should == false
|
450
|
+
end
|
451
|
+
|
452
|
+
it "should only save the child when the parent isn't new" do
|
453
|
+
CouchObject::Database.should_receive(:open).exactly(1).and_return(@db)
|
454
|
+
@db.should_receive(:post).exactly(1).and_return(@document_response)
|
455
|
+
@person.life = @life
|
456
|
+
# fake the parent into being an old object
|
457
|
+
@person.new?.should == true
|
458
|
+
@person.instance_variable_set("@id", 123)
|
459
|
+
@person.instance_variable_set("@revision", 123)
|
460
|
+
@person.new?.should == false
|
461
|
+
|
462
|
+
@life.save
|
463
|
+
|
464
|
+
@life.new?.should == false
|
465
|
+
end
|
466
|
+
|
467
|
+
|
468
|
+
|
469
|
+
|
470
|
+
end
|