dm-constraints 0.9.11 → 0.10.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 → History.rdoc} +4 -2
- data/Manifest.txt +3 -5
- data/{README.txt → README.rdoc} +0 -0
- data/Rakefile +2 -3
- data/lib/dm-constraints/delete_constraint.rb +37 -106
- data/lib/dm-constraints/migrations.rb +274 -0
- data/lib/dm-constraints/version.rb +1 -1
- data/lib/dm-constraints.rb +27 -49
- data/spec/integration/constraints_spec.rb +380 -339
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +50 -12
- data/tasks/install.rb +1 -1
- data/tasks/spec.rb +4 -4
- metadata +15 -24
- data/lib/dm-constraints/data_objects_adapter.rb +0 -197
- data/lib/dm-constraints/mysql_adapter.rb +0 -50
- data/lib/dm-constraints/postgres_adapter.rb +0 -32
@@ -1,566 +1,607 @@
|
|
1
|
-
require '
|
2
|
-
require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
|
1
|
+
require 'spec_helper'
|
3
2
|
|
4
|
-
ADAPTERS.each do |
|
5
|
-
describe 'DataMapper::Constraints' do
|
6
|
-
before do
|
7
|
-
DataMapper
|
3
|
+
ADAPTERS.each do |name, connection_uri|
|
4
|
+
describe 'DataMapper::Constraints', "(with #{name})" do
|
5
|
+
before :all do
|
6
|
+
@adapter = DataMapper.setup(:default, connection_uri)
|
7
|
+
@repository = DataMapper.repository(@adapter.name)
|
8
8
|
|
9
|
-
class ::
|
9
|
+
class ::Article
|
10
10
|
include DataMapper::Resource
|
11
11
|
include DataMapper::Constraints
|
12
12
|
|
13
|
-
property :id,
|
14
|
-
property :
|
15
|
-
property :
|
13
|
+
property :id, Serial
|
14
|
+
property :title, String, :nullable => false
|
15
|
+
property :content, Text
|
16
16
|
|
17
|
-
has
|
17
|
+
has 1, :revision
|
18
|
+
has n, :comments
|
19
|
+
has n, :authors, :through => Resource
|
18
20
|
end
|
19
21
|
|
20
|
-
class ::
|
22
|
+
class ::Author
|
21
23
|
include DataMapper::Resource
|
22
24
|
include DataMapper::Constraints
|
23
25
|
|
24
26
|
property :first_name, String, :key => true
|
25
27
|
property :last_name, String, :key => true
|
26
28
|
|
27
|
-
has n, :
|
29
|
+
has n, :comments
|
30
|
+
has n, :articles, :through => Resource
|
28
31
|
end
|
29
32
|
|
30
|
-
class ::
|
31
|
-
include DataMapper::Resource
|
32
|
-
include DataMapper::Constraints
|
33
|
-
|
34
|
-
property :id, Serial
|
35
|
-
property :name, String
|
36
|
-
property :breed, String
|
37
|
-
|
38
|
-
belongs_to :stable
|
39
|
-
belongs_to :farmer
|
40
|
-
end
|
41
|
-
|
42
|
-
#Used to test a belongs_to association with no has() association
|
43
|
-
#on the other end
|
44
|
-
class ::Pig
|
33
|
+
class ::Comment
|
45
34
|
include DataMapper::Resource
|
46
35
|
include DataMapper::Constraints
|
47
36
|
|
48
37
|
property :id, Serial
|
49
|
-
property :
|
38
|
+
property :body, Text
|
50
39
|
|
51
|
-
belongs_to :
|
40
|
+
belongs_to :article
|
41
|
+
belongs_to :author
|
52
42
|
end
|
53
43
|
|
54
|
-
#Used to test
|
55
|
-
|
44
|
+
# Used to test a belongs_to association with no has() association
|
45
|
+
# on the other end
|
46
|
+
class ::Revision
|
56
47
|
include DataMapper::Resource
|
57
48
|
include DataMapper::Constraints
|
58
49
|
|
59
50
|
property :id, Serial
|
60
|
-
property :
|
51
|
+
property :text, String
|
61
52
|
|
62
|
-
|
53
|
+
belongs_to :article
|
63
54
|
end
|
55
|
+
end
|
64
56
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
57
|
+
describe 'create related objects' do
|
58
|
+
before :all do
|
59
|
+
class ::Comment
|
60
|
+
belongs_to :article, :nullable => true
|
61
|
+
belongs_to :author, :nullable => true
|
62
|
+
end
|
71
63
|
|
72
|
-
|
64
|
+
class ::Revision
|
65
|
+
belongs_to :article, :nullable => true
|
66
|
+
end
|
73
67
|
end
|
74
68
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
Cow.new.should be_kind_of(DataMapper::Constraints)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "should be able to create related objects with a foreign key constraint" do
|
83
|
-
@s = Stable.create(:location => "Hometown")
|
84
|
-
@c1 = Cow.create(:name => "Bea", :stable => @s)
|
85
|
-
end
|
69
|
+
it 'should be able to create related objects with a foreign key constraint' do
|
70
|
+
@article = Article.create(:title => 'Man on the Moon')
|
71
|
+
@comment = @article.comments.create(:body => 'So true!')
|
72
|
+
end
|
86
73
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
74
|
+
it 'should be able to create related objects with a composite foreign key constraint' do
|
75
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
76
|
+
@comment = @author.comments.create(:body => 'So true!')
|
77
|
+
end
|
91
78
|
|
92
|
-
|
93
|
-
|
94
|
-
|
79
|
+
it 'should not be able to create related objects with a failing foreign key constraint' do
|
80
|
+
article = Article.create(:title => 'Man on the Moon')
|
81
|
+
lambda { Comment.create(:body => 'So true!', :article_id => article_id.id + 1) }.should raise_error
|
82
|
+
end
|
95
83
|
end
|
96
84
|
|
97
|
-
describe
|
85
|
+
describe 'belongs_to without matching has association' do
|
98
86
|
before do
|
99
|
-
@
|
100
|
-
@
|
101
|
-
@
|
102
|
-
end
|
103
|
-
it "should destroy the parent if there are no children in the association" do
|
104
|
-
@f1.destroy.should == true
|
87
|
+
@article = Article.create(:title => 'Man on the Moon')
|
88
|
+
@other_article = Article.create(:title => 'Dolly cloned')
|
89
|
+
@revision = Revision.create(:text => 'Riveting!', :article => @other_article)
|
105
90
|
end
|
106
91
|
|
107
|
-
it
|
108
|
-
@
|
92
|
+
it 'should destroy the parent if there are no children in the association' do
|
93
|
+
@article.destroy.should be_true
|
94
|
+
@article.model.get(*@article.key).should be_nil
|
109
95
|
end
|
110
96
|
|
97
|
+
it 'the child should be destroyable' do
|
98
|
+
@revision.destroy.should be_true
|
99
|
+
@revision.model.get(*@revision.key).should be_nil
|
100
|
+
end
|
111
101
|
end
|
112
102
|
|
113
|
-
describe
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
@
|
119
|
-
@
|
120
|
-
@c1 = Cow.create(:name => "Bea", :farmer => @f2)
|
121
|
-
@f1.destroy.should == true
|
103
|
+
describe 'constraint options' do
|
104
|
+
describe 'when no constraint options are given' do
|
105
|
+
before do
|
106
|
+
@article = Article.create(:title => 'Man on the Moon')
|
107
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
108
|
+
@other_author = Author.create(:first_name => 'Joe', :last_name => 'Smith')
|
109
|
+
@comment = @other_author.comments.create(:body => 'So true!', :article => @article)
|
122
110
|
end
|
123
111
|
|
124
|
-
it
|
125
|
-
@
|
126
|
-
@
|
127
|
-
@f.destroy.should == false
|
112
|
+
it 'should destroy the parent if there are no children in the association' do
|
113
|
+
@author.destroy.should be_true
|
114
|
+
@author.model.get(*@author.key).should be_nil
|
128
115
|
end
|
129
116
|
|
117
|
+
it 'should not destroy the parent if there are children in the association' do
|
118
|
+
@other_author.destroy.should be_false
|
119
|
+
@other_author.model.get(*@other_author.key).should_not be_nil
|
120
|
+
end
|
130
121
|
end
|
131
122
|
|
132
|
-
describe
|
133
|
-
before do
|
134
|
-
class ::
|
135
|
-
has
|
136
|
-
has
|
137
|
-
|
138
|
-
class ::Pig
|
139
|
-
belongs_to :farmer
|
123
|
+
describe 'when :constraint => :protect is given' do
|
124
|
+
before :all do
|
125
|
+
class ::Article
|
126
|
+
has 1, :revision, :constraint => :protect
|
127
|
+
has n, :comments, :constraint => :protect
|
128
|
+
has n, :authors, :constraint => :protect, :through => Resource
|
140
129
|
end
|
141
|
-
|
142
|
-
|
130
|
+
|
131
|
+
class ::Author
|
132
|
+
has n, :comments, :constraint => :protect
|
133
|
+
has n, :articles, :constraint => :protect, :through => Resource
|
143
134
|
end
|
144
|
-
|
145
|
-
|
135
|
+
|
136
|
+
class ::Comment
|
137
|
+
belongs_to :article
|
138
|
+
belongs_to :author
|
146
139
|
end
|
147
|
-
|
148
|
-
|
140
|
+
|
141
|
+
class ::Revision
|
142
|
+
belongs_to :article
|
149
143
|
end
|
150
144
|
end
|
151
145
|
|
152
|
-
describe
|
146
|
+
describe 'one-to-one associations' do
|
153
147
|
before do
|
154
|
-
@
|
155
|
-
@
|
148
|
+
@article = Article.create(:title => 'Man on the Moon')
|
149
|
+
@revision = Revision.create(:text => 'Riveting!', :article => @article)
|
156
150
|
end
|
157
151
|
|
158
|
-
it
|
159
|
-
@
|
152
|
+
it 'should not destroy the parent if there are children in the association' do
|
153
|
+
@article.destroy.should be_false
|
154
|
+
@article.model.get(*@article.key).should_not be_nil
|
160
155
|
end
|
161
156
|
|
162
|
-
it
|
163
|
-
@
|
157
|
+
it 'the child should be destroyable' do
|
158
|
+
@revision.destroy.should be_true
|
159
|
+
@revision.model.get(*@revision.key).should be_nil
|
164
160
|
end
|
165
161
|
end
|
166
162
|
|
167
|
-
describe
|
163
|
+
describe 'one-to-many associations' do
|
168
164
|
before do
|
169
|
-
@
|
170
|
-
@
|
171
|
-
@
|
165
|
+
@article = Article.create(:title => 'Man on the Moon')
|
166
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
167
|
+
@another_author = Author.create(:first_name => 'Joe', :last_name => 'Smith')
|
168
|
+
@comment = @another_author.comments.create(:body => 'So true!', :article => @article)
|
172
169
|
end
|
173
170
|
|
174
|
-
it
|
175
|
-
@
|
171
|
+
it 'should destroy the parent if there are no children in the association' do
|
172
|
+
@author.destroy.should be_true
|
173
|
+
@author.model.get(*@author.key).should be_nil
|
176
174
|
end
|
177
175
|
|
178
|
-
it
|
179
|
-
@
|
176
|
+
it 'should not destroy the parent if there are children in the association' do
|
177
|
+
@another_author.destroy.should be_false
|
180
178
|
end
|
181
179
|
|
182
|
-
it
|
183
|
-
@
|
180
|
+
it 'the child should be destroyable' do
|
181
|
+
@comment.destroy.should be_true
|
182
|
+
@comment.model.get(*@comment.key).should be_nil
|
184
183
|
end
|
185
184
|
end
|
186
185
|
|
187
|
-
describe
|
186
|
+
describe 'many-to-many associations' do
|
188
187
|
before do
|
189
|
-
@
|
190
|
-
@
|
191
|
-
@
|
188
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
189
|
+
@another_author = Author.create(:first_name => 'Joe', :last_name => 'Smith')
|
190
|
+
@article = Article.create(:title => 'Man on the Moon', :authors => [ @author ])
|
192
191
|
end
|
193
192
|
|
194
|
-
it
|
195
|
-
@
|
193
|
+
it 'should destroy the parent if there are no children in the association' do
|
194
|
+
@another_author.destroy.should be_true
|
195
|
+
@another_author.model.get(*@another_author.key).should be_nil
|
196
196
|
end
|
197
197
|
|
198
|
-
it
|
199
|
-
@
|
198
|
+
it 'should not destroy the parent if there are children in the association' do
|
199
|
+
@author.articles.should_not == []
|
200
|
+
@author.destroy.should be_false
|
200
201
|
end
|
201
202
|
|
202
|
-
it
|
203
|
-
@
|
204
|
-
@
|
205
|
-
@
|
203
|
+
it 'the child should be destroyable' do
|
204
|
+
@article.authors.clear
|
205
|
+
@article.save.should be_true
|
206
|
+
@article.authors.should be_empty
|
206
207
|
end
|
207
208
|
end
|
209
|
+
end
|
208
210
|
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
has n, :
|
215
|
-
end
|
216
|
-
class ::Cow
|
217
|
-
belongs_to :farmer
|
211
|
+
describe 'when :constraint => :destroy! is given' do
|
212
|
+
before :all do
|
213
|
+
class ::Article
|
214
|
+
has 1, :revision, :constraint => :destroy!
|
215
|
+
has n, :comments, :constraint => :destroy!
|
216
|
+
has n, :authors, :constraint => :destroy!, :through => Resource
|
218
217
|
end
|
219
|
-
|
220
|
-
|
218
|
+
|
219
|
+
class ::Author
|
220
|
+
has n, :comments, :constraint => :destroy!
|
221
|
+
has n, :articles, :constraint => :destroy!, :through => Resource
|
221
222
|
end
|
222
|
-
|
223
|
-
|
223
|
+
|
224
|
+
class ::Comment
|
225
|
+
belongs_to :article
|
226
|
+
belongs_to :author
|
224
227
|
end
|
225
228
|
|
226
|
-
|
229
|
+
class ::Revision
|
230
|
+
belongs_to :article
|
231
|
+
end
|
227
232
|
end
|
228
233
|
|
229
|
-
describe
|
230
|
-
before
|
231
|
-
@
|
232
|
-
@
|
233
|
-
@c2 = Cow.create(:name => "Riksa", :farmer => @f)
|
234
|
+
describe 'one-to-one associations' do
|
235
|
+
before do
|
236
|
+
@article = Article.create(:title => 'Man on the Moon')
|
237
|
+
@revision = Revision.create(:text => 'Riveting!', :article => @article)
|
234
238
|
end
|
235
239
|
|
236
|
-
it
|
237
|
-
@
|
238
|
-
@
|
240
|
+
it 'should let the parent to be destroyed' do
|
241
|
+
@article.destroy.should be_true
|
242
|
+
@article.model.get(*@article.key).should be_nil
|
239
243
|
end
|
240
244
|
|
241
|
-
it
|
242
|
-
@
|
243
|
-
@
|
245
|
+
it 'should destroy the children' do
|
246
|
+
revision = @article.revision
|
247
|
+
@article.destroy.should be_true
|
248
|
+
revision.model.get(*revision.key).should be_nil
|
244
249
|
end
|
245
250
|
|
246
|
-
it
|
247
|
-
@
|
251
|
+
it 'the child should be destroyable' do
|
252
|
+
@revision.destroy.should be_true
|
253
|
+
@revision.model.get(*@revision.key).should be_nil
|
248
254
|
end
|
249
|
-
|
250
255
|
end
|
251
256
|
|
252
|
-
describe
|
257
|
+
describe 'one-to-many associations' do
|
253
258
|
before do
|
254
|
-
@
|
255
|
-
@
|
256
|
-
@
|
259
|
+
@article = Article.create(:title => 'Man on the Moon')
|
260
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
261
|
+
@comment = @author.comments.create(:body => 'So true!', :article => @article)
|
262
|
+
@another_comment = @author.comments.create(:body => 'Nice comment', :article => @article)
|
257
263
|
end
|
258
264
|
|
259
|
-
it
|
260
|
-
@
|
261
|
-
@
|
265
|
+
it 'should let the parent to be destroyed' do
|
266
|
+
@author.destroy.should be_true
|
267
|
+
@author.model.get(*@author.key).should be_nil
|
268
|
+
end
|
262
269
|
|
263
|
-
|
264
|
-
|
265
|
-
@
|
266
|
-
@t2.should_not be_new_record
|
270
|
+
it 'should destroy the children' do
|
271
|
+
@author.destroy.should be_true
|
272
|
+
@author.comments.all? { |comment| comment.should be_new }
|
267
273
|
end
|
268
274
|
|
269
|
-
it
|
270
|
-
@
|
275
|
+
it 'the child should be destroyable' do
|
276
|
+
@comment.destroy.should be_true
|
277
|
+
@comment.model.get(*@comment.key).should be_nil
|
271
278
|
end
|
272
279
|
end
|
273
280
|
|
274
|
-
|
281
|
+
describe 'many-to-many associations' do
|
282
|
+
before do
|
283
|
+
@article = Article.create(:title => 'Man on the Moon')
|
284
|
+
@other_article = Article.create(:title => 'Dolly cloned')
|
285
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe', :articles => [ @article, @other_article ])
|
286
|
+
end
|
275
287
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
has n, :cows, :constraint => :destroy
|
280
|
-
has 1, :pig, :constraint => :destroy
|
288
|
+
it 'should let the parent to be destroyed' do
|
289
|
+
@author.destroy.should be_true
|
290
|
+
@author.model.get(*@author.key).should be_nil
|
281
291
|
end
|
282
|
-
|
283
|
-
|
292
|
+
|
293
|
+
it 'should destroy the children' do
|
294
|
+
@author.destroy.should be_true
|
295
|
+
@article.model.get(*@article.key).should be_nil
|
296
|
+
@other_article.model.get(*@other_article.key).should be_nil
|
284
297
|
end
|
285
|
-
|
286
|
-
|
298
|
+
|
299
|
+
it 'the child should be destroyable' do
|
300
|
+
@article.destroy.should be_true
|
301
|
+
@article.model.get(*@article.key).should be_nil
|
287
302
|
end
|
288
|
-
|
289
|
-
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
describe 'when :constraint => :destroy is given' do
|
307
|
+
before :all do
|
308
|
+
class ::Article
|
309
|
+
has 1, :revision, :constraint => :destroy
|
310
|
+
has n, :comments, :constraint => :destroy
|
311
|
+
has n, :authors, :constraint => :destroy, :through => Resource
|
290
312
|
end
|
291
313
|
|
292
|
-
|
314
|
+
class ::Author
|
315
|
+
has n, :comments, :constraint => :destroy
|
316
|
+
has n, :articles, :constraint => :destroy, :through => Resource
|
317
|
+
end
|
318
|
+
|
319
|
+
class ::Comment
|
320
|
+
belongs_to :article
|
321
|
+
belongs_to :author
|
322
|
+
end
|
323
|
+
|
324
|
+
class ::Revision
|
325
|
+
belongs_to :article
|
326
|
+
end
|
293
327
|
end
|
294
328
|
|
295
|
-
describe
|
329
|
+
describe 'one-to-one associations' do
|
296
330
|
before do
|
297
|
-
@
|
298
|
-
@
|
331
|
+
@article = Article.create(:title => 'Man on the Moon')
|
332
|
+
@revision = Revision.create(:text => 'Riveting!', :article => @article)
|
299
333
|
end
|
300
334
|
|
301
|
-
it
|
302
|
-
@
|
303
|
-
@
|
335
|
+
it 'should let the parent to be destroyed' do
|
336
|
+
@article.destroy.should be_true
|
337
|
+
@article.model.get(*@article.key).should be_nil
|
304
338
|
end
|
305
339
|
|
306
|
-
it
|
307
|
-
|
308
|
-
@
|
309
|
-
|
340
|
+
it 'should destroy the children' do
|
341
|
+
revision = @article.revision
|
342
|
+
@article.destroy.should be_true
|
343
|
+
revision.model.get(*revision.key).should be_nil
|
310
344
|
end
|
311
345
|
|
312
|
-
it
|
313
|
-
@
|
346
|
+
it 'the child should be destroyable' do
|
347
|
+
@revision.destroy.should be_true
|
348
|
+
@revision.model.get(*@revision.key).should be_nil
|
314
349
|
end
|
315
350
|
end
|
316
351
|
|
317
|
-
describe
|
318
|
-
before
|
319
|
-
@
|
320
|
-
@
|
321
|
-
@
|
352
|
+
describe 'one-to-many associations' do
|
353
|
+
before do
|
354
|
+
@article = Article.create(:title => 'Man on the Moon')
|
355
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
356
|
+
@comment = @author.comments.create(:body => 'So true!', :article => @article)
|
357
|
+
@other_comment = @author.comments.create(:body => "That's nonsense", :article => @article)
|
322
358
|
end
|
323
359
|
|
324
|
-
it
|
325
|
-
@
|
326
|
-
@
|
360
|
+
it 'should let the parent to be destroyed' do
|
361
|
+
@author.destroy.should be_true
|
362
|
+
@author.model.get(*@author.key).should be_nil
|
327
363
|
end
|
328
364
|
|
329
|
-
it
|
330
|
-
@
|
331
|
-
@
|
332
|
-
@f.should be_new_record
|
365
|
+
it 'should destroy the children' do
|
366
|
+
@author.destroy.should be_true
|
367
|
+
@author.comments.all? { |comment| comment.should be_new }
|
333
368
|
end
|
334
369
|
|
335
|
-
it
|
336
|
-
@
|
370
|
+
it 'the child should be destroyable' do
|
371
|
+
@comment.destroy.should be_true
|
372
|
+
@comment.model.get(*@comment.key).should be_nil
|
337
373
|
end
|
338
|
-
|
339
374
|
end
|
340
375
|
|
341
|
-
describe
|
376
|
+
describe 'many-to-many associations' do
|
342
377
|
before do
|
343
|
-
@
|
344
|
-
@
|
345
|
-
@
|
378
|
+
@article = Article.create(:title => 'Man on the Moon')
|
379
|
+
@other_article = Article.create(:title => 'Dolly cloned')
|
380
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe', :articles => [ @article, @other_article ])
|
346
381
|
end
|
347
382
|
|
348
|
-
it
|
349
|
-
@
|
350
|
-
@
|
383
|
+
it 'should destroy the parent and the children, too' do
|
384
|
+
@author.destroy.should be_true
|
385
|
+
@author.model.get(*@author.key).should be_nil
|
351
386
|
|
352
|
-
|
353
|
-
|
354
|
-
@t1.should_not be_new_record
|
355
|
-
@t2.should_not be_new_record
|
387
|
+
@article.model.get(*@article.key).should be_nil
|
388
|
+
@other_article.model.get(*@other_article.key).should be_nil
|
356
389
|
end
|
357
390
|
|
358
|
-
it
|
359
|
-
@
|
391
|
+
it 'the child should be destroyable' do
|
392
|
+
@article.destroy.should be_true
|
393
|
+
@article.model.get(*@article.key).should be_nil
|
360
394
|
end
|
361
395
|
end
|
396
|
+
end
|
362
397
|
|
363
|
-
|
398
|
+
describe 'when :constraint => :set_nil is given' do
|
399
|
+
before :all do
|
400
|
+
# NOTE: M:M Relationships are not supported by :set_nil,
|
401
|
+
# see 'when checking constraint types' tests at bottom
|
364
402
|
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
has n, :cows, :constraint => :set_nil
|
369
|
-
has 1, :pig, :constraint => :set_nil
|
403
|
+
class ::Article
|
404
|
+
has 1, :revision, :constraint => :set_nil
|
405
|
+
has n, :comments, :constraint => :set_nil
|
370
406
|
end
|
371
|
-
|
372
|
-
|
407
|
+
|
408
|
+
class ::Author
|
409
|
+
has n, :comments, :constraint => :set_nil
|
410
|
+
end
|
411
|
+
|
412
|
+
class ::Comment
|
413
|
+
belongs_to :article, :nullable => true
|
414
|
+
belongs_to :author, :nullable => true
|
415
|
+
end
|
416
|
+
|
417
|
+
class ::Revision
|
418
|
+
belongs_to :article, :nullable => true
|
373
419
|
end
|
374
|
-
# NOTE: M:M Relationships are not supported,
|
375
|
-
# see "when checking constraint types" tests at bottom
|
376
|
-
DataMapper.auto_migrate!
|
377
420
|
end
|
378
421
|
|
379
|
-
describe
|
422
|
+
describe 'one-to-one associations' do
|
380
423
|
before do
|
381
|
-
@
|
382
|
-
@
|
424
|
+
@article = Article.create(:title => 'Man on the Moon')
|
425
|
+
@revision = Revision.create(:text => 'Riveting!', :article => @article)
|
383
426
|
end
|
384
427
|
|
385
|
-
it
|
386
|
-
@
|
428
|
+
it 'should let the parent to be destroyed' do
|
429
|
+
@article.destroy.should be_true
|
430
|
+
@article.model.get(*@article.key).should be_nil
|
387
431
|
end
|
388
432
|
|
389
433
|
it "should set the child's foreign_key id to nil" do
|
390
|
-
|
391
|
-
@
|
392
|
-
|
434
|
+
revision = @article.revision
|
435
|
+
@article.destroy.should be_true
|
436
|
+
revision.article.should be_nil
|
437
|
+
revision.model.get(*revision.key).article.should be_nil
|
393
438
|
end
|
394
439
|
|
395
|
-
it
|
396
|
-
@
|
440
|
+
it 'the child should be destroyable' do
|
441
|
+
@revision.destroy.should be_true
|
442
|
+
@revision.model.get(*@revision.key).should be_nil
|
397
443
|
end
|
398
|
-
|
399
444
|
end
|
400
445
|
|
401
|
-
describe
|
402
|
-
before
|
403
|
-
@
|
404
|
-
@
|
405
|
-
@
|
446
|
+
describe 'one-to-many associations' do
|
447
|
+
before do
|
448
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
449
|
+
@comment = @author.comments.create(:body => 'So true!')
|
450
|
+
@other_comment = @author.comments.create(:body => "That's nonsense")
|
406
451
|
end
|
407
452
|
|
408
|
-
it
|
409
|
-
@
|
410
|
-
@
|
453
|
+
it 'should let the parent to be destroyed' do
|
454
|
+
@author.destroy.should be_true
|
455
|
+
@author.model.get(*@author.key).should be_nil
|
411
456
|
end
|
412
457
|
|
413
|
-
it
|
414
|
-
@
|
415
|
-
@
|
458
|
+
it 'should set the foreign_key ids of children to nil' do
|
459
|
+
@author.destroy.should be_true
|
460
|
+
@author.comments.all? { |comment| comment.author.should be_nil }
|
416
461
|
end
|
417
462
|
|
418
|
-
it
|
419
|
-
@
|
420
|
-
@
|
421
|
-
end
|
463
|
+
it 'the children should be destroyable' do
|
464
|
+
@comment.destroy.should be_true
|
465
|
+
@comment.model.get(*@comment.key).should be_nil
|
422
466
|
|
467
|
+
@other_comment.destroy.should be_true
|
468
|
+
@other_comment.model.get(*@other_comment.key).should be_nil
|
469
|
+
end
|
423
470
|
end
|
471
|
+
end
|
424
472
|
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
has n, :
|
431
|
-
has 1, :pig, :constraint => :skip
|
473
|
+
describe 'when :constraint => :skip is given' do
|
474
|
+
before :all do
|
475
|
+
class ::Article
|
476
|
+
has 1, :revision, :constraint => :skip
|
477
|
+
has n, :comments, :constraint => :skip
|
478
|
+
has n, :authors, :constraint => :skip, :through => Resource
|
432
479
|
end
|
433
|
-
|
434
|
-
|
480
|
+
|
481
|
+
class ::Author
|
482
|
+
has n, :comments, :constraint => :skip
|
483
|
+
has n, :articles, :constraint => :skip, :through => Resource
|
435
484
|
end
|
436
|
-
|
437
|
-
|
485
|
+
|
486
|
+
class ::Comment
|
487
|
+
belongs_to :article
|
488
|
+
belongs_to :author
|
438
489
|
end
|
439
|
-
|
440
|
-
|
490
|
+
|
491
|
+
class ::Revision
|
492
|
+
belongs_to :article
|
441
493
|
end
|
442
|
-
DataMapper.auto_migrate!
|
443
494
|
end
|
444
495
|
|
445
|
-
describe
|
496
|
+
describe 'one-to-one associations' do
|
446
497
|
before do
|
447
|
-
@
|
448
|
-
@
|
498
|
+
@article = Article.create(:title => 'Man on the Moon')
|
499
|
+
@revision = Revision.create(:text => 'Riveting!', :article => @article)
|
449
500
|
end
|
450
501
|
|
451
|
-
it
|
452
|
-
@
|
453
|
-
@
|
454
|
-
# @p.farmer.should be_new_record
|
502
|
+
it 'should let the parent be destroyed' do
|
503
|
+
@article.destroy.should be_true
|
504
|
+
@article.model.get(*@article.key).should be_nil
|
455
505
|
end
|
456
506
|
|
457
|
-
it
|
458
|
-
@
|
459
|
-
@
|
507
|
+
it 'should let the children become orphan records' do
|
508
|
+
@article.destroy.should be_true
|
509
|
+
@revision.model.get(*@revision.key).article.should be_nil
|
460
510
|
end
|
461
511
|
|
462
|
-
it
|
463
|
-
@
|
512
|
+
it 'the child should be destroyable' do
|
513
|
+
@revision.destroy.should be_true
|
514
|
+
@revision.model.get(*@revision.key).should be_nil
|
464
515
|
end
|
465
|
-
|
466
516
|
end
|
467
517
|
|
468
|
-
describe
|
518
|
+
describe 'one-to-many associations' do
|
469
519
|
before do
|
470
|
-
@
|
471
|
-
@
|
472
|
-
@
|
520
|
+
@article = Article.create(:title => 'Man on the Moon')
|
521
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe')
|
522
|
+
@comment = @author.comments.create(:body => 'So true!', :article => @article)
|
523
|
+
@other_comment = @author.comments.create(:body => "That's nonsense", :article => @article)
|
473
524
|
end
|
474
525
|
|
475
|
-
it
|
476
|
-
@
|
477
|
-
@
|
526
|
+
it 'should let the parent to be destroyed' do
|
527
|
+
@author.destroy.should be_true
|
528
|
+
@author.model.get(*@author.key).should be_nil
|
478
529
|
end
|
479
530
|
|
480
|
-
it
|
481
|
-
@
|
482
|
-
@
|
483
|
-
@
|
531
|
+
it 'should let the children become orphan records' do
|
532
|
+
@author.destroy.should be_true
|
533
|
+
@comment.model.get(*@comment.key).author.should be_nil
|
534
|
+
@other_comment.model.get(*@other_comment.key).author.should be_nil
|
484
535
|
end
|
485
536
|
|
486
|
-
it
|
487
|
-
@
|
488
|
-
@
|
537
|
+
it 'the children should be destroyable' do
|
538
|
+
@comment.destroy.should be_true
|
539
|
+
@other_comment.destroy.should be_true
|
540
|
+
@other_comment.model.get(*@other_comment.key).should be_nil
|
489
541
|
end
|
490
|
-
|
491
542
|
end
|
492
543
|
|
493
|
-
describe
|
544
|
+
describe 'many-to-many associations' do
|
494
545
|
before do
|
495
|
-
@
|
496
|
-
@
|
546
|
+
@article = Article.create(:title => 'Man on the Moon')
|
547
|
+
@other_article = Article.create(:title => 'Dolly cloned')
|
548
|
+
@author = Author.create(:first_name => 'John', :last_name => 'Doe', :articles => [ @article, @other_article ])
|
497
549
|
end
|
498
550
|
|
499
|
-
it
|
500
|
-
@
|
551
|
+
it 'the children should be destroyable' do
|
552
|
+
@article.destroy.should be_true
|
553
|
+
@article.model.get(*@article.key).should be_nil
|
501
554
|
end
|
502
555
|
end
|
556
|
+
end
|
503
557
|
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
#M:M relationships results in a join table composed of a two part primary key
|
509
|
-
# setting a portion of the primary key is not possible for two reasons:
|
558
|
+
describe 'when checking constraint types' do
|
559
|
+
# M:M relationships results in a join table composed of composite (composed of two parts)
|
560
|
+
# primary key.
|
561
|
+
# Setting a portion of this primary key is not possible for two reasons:
|
510
562
|
# 1. the columns are defined as :nullable => false
|
511
563
|
# 2. there could be duplicate rows if more than one of either of the types
|
512
564
|
# was deleted while being associated to the same type on the other side of the relationshp
|
513
565
|
# Given
|
514
|
-
#
|
515
|
-
#
|
516
|
-
#
|
517
|
-
#
|
566
|
+
# Author(name: John Doe, ID: 1) =>
|
567
|
+
# Articles[Article(title: Man on the Moon, ID: 1), Article(title: Dolly cloned, ID: 2)]
|
568
|
+
# Author(Name: James Duncan, ID: 2) =>
|
569
|
+
# Articles[Article(title: Man on the Moon, ID: 1), Article(title: The end is nigh, ID: 3)]
|
518
570
|
#
|
519
|
-
# Table
|
571
|
+
# Table authors_articles would look like (author_id, article_id)
|
520
572
|
# (1, 1)
|
521
573
|
# (1, 2)
|
522
574
|
# (2, 1)
|
523
575
|
# (2, 3)
|
524
576
|
#
|
525
|
-
# If both
|
577
|
+
# If both articles were deleted and the primary key was set to null
|
526
578
|
# (null, 1)
|
527
579
|
# (null, 2)
|
528
|
-
# (null, 1) #
|
580
|
+
# (null, 1) # duplicate error!
|
529
581
|
# (null, 3)
|
530
582
|
#
|
531
583
|
# I would suggest setting :constraint to :skip in this scenario which will leave
|
532
584
|
# you with orphaned rows.
|
533
|
-
it
|
534
|
-
lambda{
|
535
|
-
class ::
|
536
|
-
has n, :
|
537
|
-
end
|
538
|
-
class ::Tag
|
539
|
-
has n, :chickens, :through => Resource, :constraint => :set_nil
|
585
|
+
it 'should raise an error if :set_nil is given for a M:M relationship' do
|
586
|
+
lambda {
|
587
|
+
class ::Article
|
588
|
+
has n, :authors, :through => Resource, :constraint => :set_nil
|
540
589
|
end
|
541
|
-
}.should raise_error(ArgumentError)
|
542
|
-
end
|
543
590
|
|
544
|
-
|
545
|
-
|
546
|
-
lambda do
|
547
|
-
class ::Farmer
|
548
|
-
has 1, :pig, :constraint => :destroy!
|
591
|
+
class ::Author
|
592
|
+
has n, :articles, :through => Resource, :constraint => :set_nil
|
549
593
|
end
|
550
|
-
|
594
|
+
}.should raise_error(ArgumentError)
|
551
595
|
end
|
552
596
|
|
553
|
-
it
|
597
|
+
it 'should raise an error if an unknown type is given' do
|
554
598
|
lambda do
|
555
|
-
class ::
|
556
|
-
has n, :
|
599
|
+
class ::Author
|
600
|
+
has n, :articles, :constraint => :chocolate
|
557
601
|
end
|
558
602
|
end.should raise_error(ArgumentError)
|
559
603
|
end
|
560
|
-
|
561
604
|
end
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
end # DataMapper::Constraints
|
566
|
-
end # ADAPTERS.each
|
605
|
+
end
|
606
|
+
end
|
607
|
+
end
|