sbf-dm-constraints 1.3.0.beta

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