couchbase-model-relationship 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,139 @@
1
+ require 'spec_helper'
2
+
3
+ class DirtyTest < Couchbase::Model
4
+ attribute :name
5
+ attribute :complex
6
+ end
7
+
8
+ describe "Dirty" do
9
+ subject { DirtyTest.new }
10
+
11
+ it "should mark the fields as dirty" do
12
+ subject.name = 'abc'
13
+ subject.should be_name_changed
14
+ end
15
+
16
+ it "should mark complex fields" do
17
+ inner = []
18
+ outer = [inner]
19
+
20
+ subject.complex = outer
21
+ subject.send :clean!
22
+
23
+ subject.complex_will_change!
24
+ subject.complex[0].push 'abc'
25
+
26
+ subject.should be_complex_changed
27
+ subject.complex.should eq([['abc']])
28
+ subject.complex_was.should eq([[]])
29
+ end
30
+
31
+ it "should not mark the field dirty when the value is the same" do
32
+ subject.name = "abc"
33
+ subject.send :clean!
34
+
35
+ subject.name = "abc"
36
+
37
+ subject.should_not be_name_changed
38
+ end
39
+
40
+ it "doesn't mark any fields as dirty when the model is loaded" do
41
+ DirtyTest.stubs(bucket: stub)
42
+ DirtyTest.bucket.expects(:get).with(['abc123'], quiet: false, extended: true).returns({'name' => "Bob"}, {}, 123)
43
+
44
+ DirtyTest.find('abc123').should_not be_changed
45
+ end
46
+
47
+ describe "creating" do
48
+ describe "successfully" do
49
+ before do
50
+ subject.stubs(create_without_dirty: true)
51
+ subject.name = "creating"
52
+ subject.create
53
+ end
54
+
55
+ it "captures changes" do
56
+ subject.name.should eq("creating")
57
+ subject.should_not be_name_changed
58
+ subject.previous_changes['name'].should eq([nil, 'creating'])
59
+ end
60
+
61
+ it "clears current changes" do
62
+ subject.changes.should be_blank
63
+ end
64
+ end
65
+
66
+ describe "failing" do
67
+ before do
68
+ subject.stubs(create_without_dirty: false)
69
+ subject.name = "creating"
70
+ subject.create
71
+ end
72
+
73
+ it "doesn't capture changes" do
74
+ subject.previous_changes.should be_blank
75
+ end
76
+
77
+ it "doesn't clear current changes" do
78
+ subject.changed.should eq(["name"])
79
+ end
80
+
81
+ it "doesn't have a previous change" do
82
+ subject.previous_name.should be_nil
83
+ end
84
+ end
85
+ end
86
+
87
+ describe "saving" do
88
+ it "doesn't saves if not changed on request" do
89
+ subject.stubs(changed?: false)
90
+ subject.expects(:save).never
91
+
92
+ subject.save_if_changed
93
+ end
94
+
95
+ it "saves if changed on request" do
96
+ subject.stubs(changed?: true)
97
+ subject.expects(:save)
98
+
99
+ subject.save_if_changed
100
+ end
101
+
102
+ describe "successfully" do
103
+ before do
104
+ subject.stubs(save_without_dirty: true)
105
+ subject.name = "save"
106
+ subject.id = 123
107
+ subject.save
108
+ end
109
+
110
+ it "captures changes" do
111
+ subject.name.should eq("save")
112
+ subject.should_not be_name_changed
113
+ subject.previous_changes['name'].should eq([nil, 'save'])
114
+ subject.previous_name.should eq(nil)
115
+ end
116
+
117
+ it "clears current changes" do
118
+ subject.changes.should be_blank
119
+ end
120
+ end
121
+
122
+ describe "failing" do
123
+ before do
124
+ subject.stubs(save_without_dirty: false)
125
+ subject.name = "save"
126
+ subject.id = 123
127
+ subject.save
128
+ end
129
+
130
+ it "doesn't capture changes" do
131
+ subject.previous_changes.should be_blank
132
+ end
133
+
134
+ it "doesn't clear current changes" do
135
+ subject.changed.should eq(["name"])
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ class IdPrefixTest < Couchbase::Model
4
+ end
5
+
6
+ describe "IdPrefix" do
7
+ subject { IdPrefixTest.new }
8
+
9
+ it "knows the proper prefix" do
10
+ subject.class.id_prefix.should eq("id_prefix_test")
11
+ end
12
+
13
+ it "prefixes an id properly" do
14
+ subject.class.prefixed_id(123).should eq("id_prefix_test:123")
15
+ end
16
+
17
+ it "unprefixes an id properly" do
18
+ subject.class.unprefixed_id("klass:123").should eq("123")
19
+ end
20
+
21
+ it "gets the prefix for an id properly" do
22
+ subject.class.prefix_from_id("class:abc").should eq("class")
23
+ end
24
+
25
+ it "gets the class for an id prperly" do
26
+ subject.class.class_from_id("id_prefix_test").should eq(IdPrefixTest)
27
+ end
28
+
29
+ describe "creating" do
30
+ before do
31
+ subject.stubs(create_without_id_prefix: true)
32
+ end
33
+
34
+ it "doesn't set the id if present" do
35
+ subject.id = 123
36
+ subject.create
37
+ subject.id.should eq(123)
38
+ end
39
+
40
+ it "creates a uid with a prefix" do
41
+ subject.create
42
+ subject.id.should match(/^id_prefix_test:/)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,282 @@
1
+ require 'spec_helper'
2
+
3
+ class Child < Couchbase::Model
4
+ attribute :age
5
+
6
+ has_parent
7
+ end
8
+
9
+ class Brother < Couchbase::Model
10
+ has_parent
11
+ end
12
+
13
+ class Sister < Couchbase::Model
14
+ has_parent
15
+ end
16
+
17
+ class ParentTest < Couchbase::Model
18
+ attribute :name
19
+
20
+ child :child
21
+ child :dont_load, auto_load: false
22
+ end
23
+
24
+ class AutoSaveTest < Couchbase::Model
25
+ include ActiveModel::Validations
26
+
27
+ attribute :name
28
+ validates_length_of :name, maximum: 5
29
+
30
+ child :child, auto_save: true
31
+ child :brother, auto_delete: true
32
+ end
33
+
34
+ class MultipleChildTest < Couchbase::Model
35
+ children :brother, :sister
36
+ end
37
+
38
+ class InvalidTest < Couchbase::Model
39
+ include ActiveModel::Validations
40
+
41
+ attribute :name
42
+ validates_length_of :name, maximum: 5
43
+ child :brother
44
+ end
45
+
46
+ describe "parent" do
47
+ subject { ParentTest.new }
48
+
49
+ it "has a setter" do
50
+ subject.should respond_to(:child=)
51
+ end
52
+
53
+ it "has a getter" do
54
+ subject.should respond_to(:child)
55
+ end
56
+
57
+ context "the getter" do
58
+ let(:association) { ParentTest.child_association_for :child }
59
+
60
+ it "returns the value is present" do
61
+ subject.child = (brother = Brother.new)
62
+ subject.child.should eq(brother)
63
+ end
64
+
65
+ it "tries to load from the db if not loaded" do
66
+ subject.expects(:build_child).never
67
+ association.expects(:load).returns((child = Child.new)).once
68
+
69
+ subject.child.should eq(child)
70
+ subject.child.should eq(child)
71
+ end
72
+
73
+ it "builds a new child if child doesn't exist in the db" do
74
+ association.expects(:load).returns(nil).once
75
+
76
+ subject.child.should be_a(Child)
77
+ subject.child.should be_a(Child)
78
+ end
79
+ end
80
+
81
+ it "can reload itself and all it's children" do
82
+ subject.child = stub(reload: true)
83
+ subject.dont_load = stub(reload: true)
84
+ subject.expects(:reload)
85
+
86
+ subject.reload_all
87
+ end
88
+
89
+ it "knows if the child is loaded or not" do
90
+ subject.should_not be_child_loaded
91
+ subject.send :child_loaded!
92
+ subject.should be_child_loaded
93
+ end
94
+
95
+ it "handles multiple children" do
96
+ MultipleChildTest.new.should respond_to(:brother, :brother=, :sister, :sister=)
97
+ end
98
+
99
+ it "saves dirty children if we want to save them" do
100
+ subject = MultipleChildTest.new
101
+ subject.brother = Brother.new
102
+ subject.brother.stubs(changed?: true)
103
+ subject.brother.expects(:save)
104
+ subject.sister = Sister.new
105
+ subject.sister.stubs(changed?: false)
106
+ subject.sister.expects(:save).never
107
+
108
+ subject.stubs(save: :saved)
109
+
110
+ subject.save_with_children.should eq(:saved)
111
+ end
112
+
113
+ it "doesn't save children if the main object isn't valid" do
114
+ subject = InvalidTest.new
115
+ subject.brother = Brother.new
116
+ subject.brother.stubs(changed?: true)
117
+ subject.brother.expects(:save).never
118
+
119
+ subject.name = "123456"
120
+
121
+ subject.save_with_children
122
+ end
123
+
124
+ it "auto-saves children marked as autosaved" do
125
+ subject = AutoSaveTest.new name: "Test"
126
+ subject.child = Child.new age: 5
127
+ subject.brother = Brother.new
128
+
129
+ subject.stubs(save_without_autosave_children: true)
130
+
131
+ subject.child.expects(:save_if_changed)
132
+ subject.brother.expects(:save_if_changed).never
133
+
134
+ subject.save
135
+ end
136
+
137
+ it "doesn't auto-save children if we fail to save" do
138
+ subject = AutoSaveTest.new name: "Test abc"
139
+ subject.child = Child.new age: 5
140
+ subject.brother = Brother.new
141
+
142
+ subject.child.expects(:save_if_changed).never
143
+ subject.brother.expects(:save_if_changed).never
144
+
145
+ subject.save
146
+ end
147
+
148
+ it "auto-deletes children marked as auto-delete" do
149
+ subject = AutoSaveTest.new name: "Test"
150
+ subject.child = Child.new age: 5
151
+ subject.brother = Brother.new
152
+
153
+ subject.stubs(delete_without_autodelete_children: true)
154
+
155
+ subject.child.expects(:delete).never
156
+ subject.brother.expects(:delete)
157
+
158
+ subject.delete
159
+ end
160
+
161
+ it "deletes children when we're deleted" do
162
+ subject = MultipleChildTest.new
163
+ subject.brother = Brother.new
164
+ subject.brother.expects(:delete)
165
+ subject.sister = Sister.new
166
+ subject.sister.expects(:delete)
167
+
168
+ subject.stubs(delete: :deleted)
169
+
170
+ subject.delete_with_children.should eq(:deleted)
171
+ end
172
+
173
+ it "builds a new object properly" do
174
+ subject.id = "parent_test:123"
175
+ child = subject.build_child age: 6
176
+
177
+ child.should eq(subject.child)
178
+ child.age.should eq(6)
179
+ child.parent.should eq(subject)
180
+ end
181
+
182
+ describe "finding objects with children" do
183
+ subject { ParentTest }
184
+ let(:bucket) { stub }
185
+
186
+ before do
187
+ subject.stubs(bucket: bucket)
188
+ end
189
+
190
+ it "finds and returns the proper objects" do
191
+ bucket.expects(:get).with(
192
+ ["parent:1", "child:1"],
193
+ quiet: true,
194
+ extended: true
195
+ ).returns({
196
+ "parent:1" => [{name: "abc"}, 0, :cas],
197
+ "child:1" => [{age: 5}, 0, :cas]
198
+ })
199
+
200
+ parent = subject.find_with_children("parent:1")
201
+ parent.name.should eq("abc")
202
+ parent.child.age.should eq(5)
203
+ end
204
+
205
+ it "finds and returns all the proper objects" do
206
+ bucket.expects(:get).with(
207
+ ["parent:1", "parent:2", 'child:1', 'child:2'],
208
+ quiet: true,
209
+ extended: true
210
+ ).returns({
211
+ "parent:1" => [{name: "abc"}, 0, :cas],
212
+ "child:2" => [{age: 5}, 0, :cas],
213
+ "parent:2" => [{name: "def"}, 0, :cas],
214
+ "child:1" => [{age: 7}, 0, :cas]
215
+ })
216
+
217
+ objects = subject.find_all_with_children(["parent:1", "parent:2"])
218
+ objects.size.should eq(2)
219
+
220
+ objects.first.id.should eq("parent:1")
221
+ objects.first.name.should eq("abc")
222
+ objects.first.child.id.should eq("child:1")
223
+ objects.first.child.age.should eq(7)
224
+
225
+ objects.last.id.should eq("parent:2")
226
+ objects.last.name.should eq('def')
227
+ objects.last.child.id.should eq("child:2")
228
+ objects.last.child.age.should eq(5)
229
+ end
230
+
231
+ it "only finds valid children" do
232
+ bucket.expects(:get).with(
233
+ ["parent:1"],
234
+ quiet: true,
235
+ extended: true
236
+ ).returns({
237
+ "parent:1" => [{name: "abc"}, 0, :cas],
238
+ })
239
+
240
+ subject.find_with_children "parent:1", :invalid
241
+ end
242
+
243
+ it "raises an error when the parent object isn't found" do
244
+ bucket.expects(:get).with(
245
+ ["parent:1", "child:1"],
246
+ quiet: true,
247
+ extended: true
248
+ ).returns({
249
+ "child:1" => [{age: 5}, 0, :cas]
250
+ })
251
+
252
+ expect { subject.find_with_children("parent:1") }.to raise_error(Couchbase::Error::NotFound)
253
+ end
254
+
255
+ it "marks all children as loaded even if they're not found" do
256
+ bucket.expects(:get).with(
257
+ ["parent:1", "child:1"],
258
+ quiet: true,
259
+ extended: true
260
+ ).returns({
261
+ "parent:1" => [{name: "abc"}, 0, :cas],
262
+ })
263
+
264
+ parent = subject.find_with_children("parent:1")
265
+ parent.should be_child_loaded
266
+ parent.child.should be_new
267
+ end
268
+
269
+ it "doesn't raise an error when the child object isn't found" do
270
+ bucket.expects(:get).with(
271
+ ["parent:1", "child:1"],
272
+ quiet: true,
273
+ extended: true
274
+ ).returns({
275
+ "parent:1" => [{name: "abc"}, 0, :cas],
276
+ })
277
+
278
+ parent = subject.find_with_children("parent:1")
279
+ parent.name.should eq("abc")
280
+ end
281
+ end
282
+ end