couchbase-model-relationship 0.1

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.
@@ -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