schema_plus 2.0.0.pre16 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +41 -58
- data/lib/schema_plus.rb +1 -1
- data/lib/schema_plus/version.rb +1 -1
- data/schema_plus.gemspec +3 -3
- data/spec/sanity_spec.rb +10 -0
- metadata +15 -27
- data/lib/schema_plus/auto_foreign_keys.rb +0 -31
- data/lib/schema_plus/auto_foreign_keys/active_record/connection_adapters/sqlite3_adapter.rb +0 -22
- data/lib/schema_plus/auto_foreign_keys/active_record/migration/command_recorder.rb +0 -14
- data/lib/schema_plus/auto_foreign_keys/middleware/migration.rb +0 -66
- data/lib/schema_plus/auto_foreign_keys/middleware/schema.rb +0 -18
- data/spec/schema_auto_foreign_keys/foreign_key_spec.rb +0 -206
- data/spec/schema_auto_foreign_keys/migration_spec.rb +0 -778
- data/spec/schema_auto_foreign_keys/schema_dumper_spec.rb +0 -256
- data/spec/schema_auto_foreign_keys/schema_spec.rb +0 -99
@@ -1,778 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
require 'spec_helper'
|
3
|
-
|
4
|
-
describe ActiveRecord::Migration do
|
5
|
-
|
6
|
-
before(:each) do
|
7
|
-
define_schema(:auto_create => true) do
|
8
|
-
|
9
|
-
create_table :users, :force => true do |t|
|
10
|
-
t.string :login, :index => { :unique => true }
|
11
|
-
end
|
12
|
-
|
13
|
-
create_table :members, :force => true do |t|
|
14
|
-
t.string :login
|
15
|
-
end
|
16
|
-
|
17
|
-
create_table :comments, :force => true do |t|
|
18
|
-
t.string :content
|
19
|
-
t.integer :user
|
20
|
-
t.integer :user_id
|
21
|
-
t.foreign_key :user_id, :users, :primary_key => :id
|
22
|
-
end
|
23
|
-
|
24
|
-
create_table :posts, :force => true do |t|
|
25
|
-
t.string :content
|
26
|
-
end
|
27
|
-
end
|
28
|
-
class User < ::ActiveRecord::Base ; end
|
29
|
-
class Post < ::ActiveRecord::Base ; end
|
30
|
-
class Comment < ::ActiveRecord::Base ; end
|
31
|
-
end
|
32
|
-
|
33
|
-
around(:each) do |example|
|
34
|
-
with_fk_config(:auto_create => true, :auto_index => true) { example.run }
|
35
|
-
end
|
36
|
-
|
37
|
-
context "when table is created" do
|
38
|
-
|
39
|
-
before(:each) do
|
40
|
-
@model = Post
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should create auto foreign keys" do
|
44
|
-
recreate_table(@model) do |t|
|
45
|
-
t.integer :user_id
|
46
|
-
end
|
47
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
48
|
-
end
|
49
|
-
|
50
|
-
it "should create explicit foreign key with default reference" do
|
51
|
-
recreate_table(@model) do |t|
|
52
|
-
t.integer :user, :foreign_key => true
|
53
|
-
end
|
54
|
-
expect(@model).to reference(:users, :id).on(:user)
|
55
|
-
end
|
56
|
-
|
57
|
-
it "should create foreign key with different reference" do
|
58
|
-
recreate_table(@model) do |t|
|
59
|
-
t.integer :author_id, :foreign_key => { :references => :users }
|
60
|
-
end
|
61
|
-
expect(@model).to reference(:users, :id).on(:author_id)
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should create foreign key without modifying input hash" do
|
65
|
-
hash = { :references => :users }
|
66
|
-
hash_original = hash.dup
|
67
|
-
recreate_table(@model) do |t|
|
68
|
-
t.integer :author_id, :foreign_key => hash
|
69
|
-
end
|
70
|
-
expect(hash).to eq(hash_original)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should create foreign key without modifying input hash" do
|
74
|
-
hash = { :references => :users }
|
75
|
-
hash_original = hash.dup
|
76
|
-
recreate_table(@model) do |t|
|
77
|
-
t.references :author, :foreign_key => hash
|
78
|
-
end
|
79
|
-
expect(hash).to eq(hash_original)
|
80
|
-
end
|
81
|
-
|
82
|
-
it "should create foreign key with different reference using shortcut" do
|
83
|
-
recreate_table(@model) do |t|
|
84
|
-
t.integer :author_id, :references => :users
|
85
|
-
end
|
86
|
-
expect(@model).to reference(:users, :id).on(:author_id)
|
87
|
-
end
|
88
|
-
|
89
|
-
it "should create foreign key with default name" do
|
90
|
-
recreate_table @model do |t|
|
91
|
-
t.integer :user_id, :foreign_key => true
|
92
|
-
end
|
93
|
-
expect(@model).to reference(:users, :id).with_name("fk_#{@model.table_name}_user_id")
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should create foreign key with specified name" do
|
97
|
-
recreate_table @model do |t|
|
98
|
-
t.integer :user_id, :foreign_key => { :name => "wugga" }
|
99
|
-
end
|
100
|
-
expect(@model).to reference(:users, :id).with_name("wugga")
|
101
|
-
end
|
102
|
-
|
103
|
-
it "should allow multiple foreign keys to be made" do
|
104
|
-
recreate_table(@model) do |t|
|
105
|
-
t.integer :user_id, :references => :users
|
106
|
-
t.integer :updater_id, :references => :users
|
107
|
-
end
|
108
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
109
|
-
expect(@model).to reference(:users, :id).on(:updater_id)
|
110
|
-
end
|
111
|
-
|
112
|
-
it "should suppress foreign key" do
|
113
|
-
recreate_table(@model) do |t|
|
114
|
-
t.integer :member_id, :foreign_key => false
|
115
|
-
end
|
116
|
-
expect(@model).not_to reference.on(:member_id)
|
117
|
-
end
|
118
|
-
|
119
|
-
it "should suppress foreign key using shortcut" do
|
120
|
-
recreate_table(@model) do |t|
|
121
|
-
t.integer :member_id, :references => nil
|
122
|
-
end
|
123
|
-
expect(@model).not_to reference.on(:member_id)
|
124
|
-
end
|
125
|
-
|
126
|
-
it "should create foreign key using t.belongs_to" do
|
127
|
-
recreate_table(@model) do |t|
|
128
|
-
t.belongs_to :user
|
129
|
-
end
|
130
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
131
|
-
end
|
132
|
-
|
133
|
-
it "should not create foreign key using t.belongs_to with :polymorphic => true" do
|
134
|
-
recreate_table(@model) do |t|
|
135
|
-
t.belongs_to :user, :polymorphic => true
|
136
|
-
end
|
137
|
-
expect(@model).not_to reference(:users, :id).on(:user_id)
|
138
|
-
end
|
139
|
-
|
140
|
-
it "should create foreign key using t.references" do
|
141
|
-
recreate_table(@model) do |t|
|
142
|
-
t.references :user
|
143
|
-
end
|
144
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
145
|
-
end
|
146
|
-
|
147
|
-
it "should not create foreign key using t.references with :foreign_key => false" do
|
148
|
-
recreate_table(@model) do |t|
|
149
|
-
t.references :user, :foreign_key => false
|
150
|
-
end
|
151
|
-
expect(@model).not_to reference(:users, :id).on(:user_id)
|
152
|
-
end
|
153
|
-
|
154
|
-
it "should not create foreign key using t.references with :polymorphic => true" do
|
155
|
-
recreate_table(@model) do |t|
|
156
|
-
t.references :user, :polymorphic => true
|
157
|
-
end
|
158
|
-
expect(@model).not_to reference(:users, :id).on(:user_id)
|
159
|
-
end
|
160
|
-
|
161
|
-
it "should create foreign key to the same table on parent_id" do
|
162
|
-
recreate_table(@model) do |t|
|
163
|
-
t.integer :parent_id
|
164
|
-
end
|
165
|
-
expect(@model).to reference(@model.table_name, :id).on(:parent_id)
|
166
|
-
end
|
167
|
-
|
168
|
-
[:references, :belongs_to].each do |reftype|
|
169
|
-
|
170
|
-
context "when define #{reftype}" do
|
171
|
-
|
172
|
-
before(:each) do
|
173
|
-
@model = Comment
|
174
|
-
end
|
175
|
-
|
176
|
-
it "should create foreign key" do
|
177
|
-
create_reference(reftype, :post)
|
178
|
-
expect(@model).to reference(:posts, :id).on(:post_id)
|
179
|
-
end
|
180
|
-
|
181
|
-
it "should not create a foreign_key if polymorphic" do
|
182
|
-
create_reference(reftype, :post, :polymorphic => true)
|
183
|
-
expect(@model).not_to reference(:posts, :id).on(:post_id)
|
184
|
-
end
|
185
|
-
|
186
|
-
it "should create an index implicitly" do
|
187
|
-
create_reference(reftype, :post)
|
188
|
-
expect(@model).to have_index.on(:post_id)
|
189
|
-
end
|
190
|
-
|
191
|
-
it "should create exactly one index explicitly (#157)" do
|
192
|
-
create_reference(reftype, :post, :index => true)
|
193
|
-
expect(@model).to have_index.on(:post_id)
|
194
|
-
end
|
195
|
-
|
196
|
-
it "should respect :unique (#157)" do
|
197
|
-
create_reference(reftype, :post, :index => :unique)
|
198
|
-
expect(@model).to have_unique_index.on(:post_id)
|
199
|
-
end
|
200
|
-
|
201
|
-
it "should create a two-column index if polymophic and index requested" do
|
202
|
-
create_reference(reftype, :post, :polymorphic => true, :index => true)
|
203
|
-
expect(@model).to have_index.on([:post_id, :post_type])
|
204
|
-
end
|
205
|
-
|
206
|
-
protected
|
207
|
-
|
208
|
-
def create_reference(reftype, column_name, *args)
|
209
|
-
recreate_table(@model) do |t|
|
210
|
-
t.send reftype, column_name, *args
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
it "should auto-index foreign keys only" do
|
218
|
-
recreate_table(@model) do |t|
|
219
|
-
t.integer :user_id
|
220
|
-
t.integer :application_id, :references => nil
|
221
|
-
t.integer :state
|
222
|
-
end
|
223
|
-
expect(@model).to have_index.on(:user_id)
|
224
|
-
expect(@model).not_to have_index.on(:application_id)
|
225
|
-
expect(@model).not_to have_index.on(:state)
|
226
|
-
end
|
227
|
-
|
228
|
-
it "should override foreign key auto_create positively" do
|
229
|
-
with_fk_config(:auto_create => false) do
|
230
|
-
recreate_table @model, :foreign_keys => {:auto_create => true} do |t|
|
231
|
-
t.integer :user_id
|
232
|
-
end
|
233
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
it "should override foreign key auto_create negatively" do
|
238
|
-
with_fk_config(:auto_create => true) do
|
239
|
-
recreate_table @model, :foreign_keys => {:auto_create => false} do |t|
|
240
|
-
t.integer :user_id
|
241
|
-
end
|
242
|
-
expect(@model).not_to reference.on(:user_id)
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
it "should override foreign key auto_index positively" do
|
247
|
-
with_fk_config(:auto_index => false) do
|
248
|
-
recreate_table @model, :foreign_keys => {:auto_index => true} do |t|
|
249
|
-
t.integer :user_id
|
250
|
-
end
|
251
|
-
expect(@model).to have_index.on(:user_id)
|
252
|
-
end
|
253
|
-
end
|
254
|
-
|
255
|
-
actions = [:cascade, :restrict, :nullify, :set_default, :no_action]
|
256
|
-
|
257
|
-
actions.each do |action|
|
258
|
-
if action == :set_default
|
259
|
-
if_action_supported = { :mysql => :skip }
|
260
|
-
if_action_unsupported = { :mysql => :only }
|
261
|
-
else
|
262
|
-
if_action_supported = { :if => true }
|
263
|
-
if_action_unsupported = { :if => false }
|
264
|
-
end
|
265
|
-
|
266
|
-
it "should create and detect on_update #{action.inspect}", if_action_supported do
|
267
|
-
recreate_table @model do |t|
|
268
|
-
t.integer :user_id, :foreign_key => { :on_update => action }
|
269
|
-
end
|
270
|
-
expect(@model).to reference.on(:user_id).on_update(action)
|
271
|
-
end
|
272
|
-
|
273
|
-
it "should create and detect on_update #{action.inspect} using shortcut", if_action_supported do
|
274
|
-
recreate_table @model do |t|
|
275
|
-
t.integer :user_id, :on_update => action
|
276
|
-
end
|
277
|
-
expect(@model).to reference.on(:user_id).on_update(action)
|
278
|
-
end
|
279
|
-
|
280
|
-
it "should raise a not-implemented error for on_update => #{action}", if_action_unsupported do
|
281
|
-
expect {
|
282
|
-
recreate_table @model do |t|
|
283
|
-
t.integer :user_id, :foreign_key => { :on_update => action }
|
284
|
-
end
|
285
|
-
}.to raise_error(NotImplementedError)
|
286
|
-
end
|
287
|
-
|
288
|
-
it "should create and detect on_delete #{action.inspect}", if_action_supported do
|
289
|
-
recreate_table @model do |t|
|
290
|
-
t.integer :user_id, :foreign_key => { :on_delete => action }
|
291
|
-
end
|
292
|
-
expect(@model).to reference.on(:user_id).on_delete(action)
|
293
|
-
end
|
294
|
-
|
295
|
-
it "should create and detect on_delete #{action.inspect} using shortcut", if_action_supported do
|
296
|
-
recreate_table @model do |t|
|
297
|
-
t.integer :user_id, :on_delete => action
|
298
|
-
end
|
299
|
-
expect(@model).to reference.on(:user_id).on_delete(action)
|
300
|
-
end
|
301
|
-
|
302
|
-
it "should raise a not-implemented error for on_delete => #{action}", if_action_unsupported do
|
303
|
-
expect {
|
304
|
-
recreate_table @model do |t|
|
305
|
-
t.integer :user_id, :foreign_key => { :on_delete => action }
|
306
|
-
end
|
307
|
-
}.to raise_error(NotImplementedError)
|
308
|
-
end
|
309
|
-
|
310
|
-
end
|
311
|
-
|
312
|
-
[false, true, :initially_deferred].each do |status|
|
313
|
-
it "should create and detect deferrable #{status.inspect}", :mysql => :skip do
|
314
|
-
recreate_table @model do |t|
|
315
|
-
t.integer :user_id, :on_delete => :cascade, :deferrable => status
|
316
|
-
end
|
317
|
-
expect(@model).to reference.on(:user_id).deferrable(status)
|
318
|
-
end
|
319
|
-
end
|
320
|
-
|
321
|
-
it "should use default on_delete action" do
|
322
|
-
with_fk_config(:on_delete => :cascade) do
|
323
|
-
recreate_table @model do |t|
|
324
|
-
t.integer :user_id
|
325
|
-
end
|
326
|
-
expect(@model).to reference.on(:user_id).on_delete(:cascade)
|
327
|
-
end
|
328
|
-
end
|
329
|
-
|
330
|
-
it "should override on_update action per table" do
|
331
|
-
with_fk_config(:on_update => :cascade) do
|
332
|
-
recreate_table @model, :foreign_keys => {:on_update => :restrict} do |t|
|
333
|
-
t.integer :user_id
|
334
|
-
end
|
335
|
-
expect(@model).to reference.on(:user_id).on_update(:restrict)
|
336
|
-
end
|
337
|
-
end
|
338
|
-
|
339
|
-
it "should override on_delete action per table" do
|
340
|
-
with_fk_config(:on_delete => :cascade) do
|
341
|
-
recreate_table @model, :foreign_keys => {:on_delete => :restrict} do |t|
|
342
|
-
t.integer :user_id
|
343
|
-
end
|
344
|
-
expect(@model).to reference.on(:user_id).on_delete(:restrict)
|
345
|
-
end
|
346
|
-
end
|
347
|
-
|
348
|
-
it "should override on_update action per column" do
|
349
|
-
with_fk_config(:on_update => :cascade) do
|
350
|
-
recreate_table @model, :foreign_keys => {:on_update => :restrict} do |t|
|
351
|
-
t.integer :user_id, :foreign_key => { :on_update => :nullify }
|
352
|
-
end
|
353
|
-
expect(@model).to reference.on(:user_id).on_update(:nullify)
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
it "should override on_delete action per column" do
|
358
|
-
with_fk_config(:on_delete => :cascade) do
|
359
|
-
recreate_table @model, :foreign_keys => {:on_delete => :restrict} do |t|
|
360
|
-
t.integer :user_id, :foreign_key => { :on_delete => :nullify }
|
361
|
-
end
|
362
|
-
expect(@model).to reference.on(:user_id).on_delete(:nullify)
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
|
-
it "should raise an error for an invalid on_update action" do
|
367
|
-
expect {
|
368
|
-
recreate_table @model do |t|
|
369
|
-
t.integer :user_id, :foreign_key => { :on_update => :invalid }
|
370
|
-
end
|
371
|
-
}.to raise_error(ArgumentError)
|
372
|
-
end
|
373
|
-
|
374
|
-
it "should raise an error for an invalid on_delete action" do
|
375
|
-
expect {
|
376
|
-
recreate_table @model do |t|
|
377
|
-
t.integer :user_id, :foreign_key => { :on_delete => :invalid }
|
378
|
-
end
|
379
|
-
}.to raise_error(ArgumentError)
|
380
|
-
end
|
381
|
-
|
382
|
-
it "should override foreign key auto_index negatively", :mysql => :skip do
|
383
|
-
with_fk_config(:auto_index => true) do
|
384
|
-
recreate_table @model, :foreign_keys => {:auto_index => false} do |t|
|
385
|
-
t.integer :user_id
|
386
|
-
end
|
387
|
-
expect(@model).not_to have_index.on(:user_id)
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
it "should disable auto-index for a column", :mysql => :skip do
|
392
|
-
with_fk_config(:auto_index => true) do
|
393
|
-
recreate_table @model do |t|
|
394
|
-
t.integer :user_id, :index => false
|
395
|
-
end
|
396
|
-
expect(@model).not_to have_index.on(:user_id)
|
397
|
-
end
|
398
|
-
end
|
399
|
-
|
400
|
-
end
|
401
|
-
|
402
|
-
context "when table is changed" do
|
403
|
-
before(:each) do
|
404
|
-
@model = Post
|
405
|
-
end
|
406
|
-
[false, true].each do |bulk|
|
407
|
-
suffix = bulk ? ' with :bulk option' : ""
|
408
|
-
|
409
|
-
it "should create a foreign key constraint"+suffix, :sqlite3 => :skip do
|
410
|
-
change_table(@model, :bulk => bulk) do |t|
|
411
|
-
t.integer :user_id
|
412
|
-
end
|
413
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
414
|
-
end
|
415
|
-
|
416
|
-
context "migrate down" do
|
417
|
-
it "should remove a foreign key constraint"+suffix, :sqlite3 => :skip do
|
418
|
-
Comment.reset_column_information
|
419
|
-
expect(Comment).to reference(:users, :id).on(:user_id)
|
420
|
-
migration = Class.new ::ActiveRecord::Migration do
|
421
|
-
define_method(:change) {
|
422
|
-
change_table("comments", :bulk => bulk) do |t|
|
423
|
-
t.integer :user_id
|
424
|
-
end
|
425
|
-
}
|
426
|
-
end
|
427
|
-
ActiveRecord::Migration.suppress_messages do
|
428
|
-
migration.migrate(:down)
|
429
|
-
end
|
430
|
-
Comment.reset_column_information
|
431
|
-
expect(Comment).not_to reference(:users, :id).on(:user_id)
|
432
|
-
end
|
433
|
-
end
|
434
|
-
|
435
|
-
it "should create a foreign key constraint using :references"+suffix, :sqlite3 => :skip do
|
436
|
-
change_table(@model, :bulk => bulk) do |t|
|
437
|
-
t.references :user
|
438
|
-
end
|
439
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
440
|
-
end
|
441
|
-
|
442
|
-
it "should accept index shorthand when using :references"+suffix, :sqlite3 => :skip do
|
443
|
-
with_fk_config(:auto_index => false) do
|
444
|
-
change_table(@model, :bulk => bulk) do |t|
|
445
|
-
t.references :user, :index => true
|
446
|
-
end
|
447
|
-
end
|
448
|
-
expect(@model).to have_index.on(:user_id)
|
449
|
-
end
|
450
|
-
|
451
|
-
|
452
|
-
it "should create a foreign key constraint using :belongs_to"+suffix, :sqlite3 => :skip do
|
453
|
-
change_table(@model, :bulk => bulk) do |t|
|
454
|
-
t.belongs_to :user
|
455
|
-
end
|
456
|
-
expect(@model).to reference(:users, :id).on(:user_id)
|
457
|
-
end
|
458
|
-
end
|
459
|
-
end
|
460
|
-
|
461
|
-
context "when column is added", :sqlite3 => :skip do
|
462
|
-
|
463
|
-
before(:each) do
|
464
|
-
@model = Comment
|
465
|
-
end
|
466
|
-
|
467
|
-
it "should create foreign key" do
|
468
|
-
add_column(:post_id, :integer) do
|
469
|
-
expect(@model).to reference(:posts, :id).on(:post_id)
|
470
|
-
end
|
471
|
-
end
|
472
|
-
|
473
|
-
it "should create foreign key to explicitly given table" do
|
474
|
-
add_column(:author_id, :integer, :foreign_key => { :references => :users }) do
|
475
|
-
expect(@model).to reference(:users, :id).on(:author_id)
|
476
|
-
end
|
477
|
-
end
|
478
|
-
|
479
|
-
it "should create foreign key to explicitly given table using shortcut" do
|
480
|
-
add_column(:author_id, :integer, :references => :users) do
|
481
|
-
expect(@model).to reference(:users, :id).on(:author_id)
|
482
|
-
end
|
483
|
-
end
|
484
|
-
|
485
|
-
it "should create foreign key to explicitly given table and column name" do
|
486
|
-
add_column(:author_login, :string, :foreign_key => { :references => [:users, :login]}) do
|
487
|
-
expect(@model).to reference(:users, :login).on(:author_login)
|
488
|
-
end
|
489
|
-
end
|
490
|
-
|
491
|
-
it "should create foreign key to the same table on parent_id" do
|
492
|
-
add_column(:parent_id, :integer) do
|
493
|
-
expect(@model).to reference(@model.table_name, :id).on(:parent_id)
|
494
|
-
end
|
495
|
-
end
|
496
|
-
|
497
|
-
it "shouldn't create foreign key if column doesn't look like foreign key" do
|
498
|
-
add_column(:views_count, :integer) do
|
499
|
-
expect(@model).not_to reference.on(:views_count)
|
500
|
-
end
|
501
|
-
end
|
502
|
-
|
503
|
-
it "shouldn't create foreign key if specified explicitly" do
|
504
|
-
add_column(:post_id, :integer, :foreign_key => false) do
|
505
|
-
expect(@model).not_to reference.on(:post_id)
|
506
|
-
end
|
507
|
-
end
|
508
|
-
|
509
|
-
it "shouldn't create foreign key if specified explicitly by shorthand" do
|
510
|
-
add_column(:post_id, :integer, :references => nil) do
|
511
|
-
expect(@model).not_to reference.on(:post_id)
|
512
|
-
end
|
513
|
-
end
|
514
|
-
|
515
|
-
it "should auto-index if specified in global options" do
|
516
|
-
SchemaPlus::ForeignKeys.config.auto_index = true
|
517
|
-
add_column(:post_id, :integer) do
|
518
|
-
expect(@model).to have_index.on(:post_id)
|
519
|
-
end
|
520
|
-
SchemaPlus::ForeignKeys.config.auto_index = false
|
521
|
-
end
|
522
|
-
|
523
|
-
it "should auto-index foreign keys only" do
|
524
|
-
SchemaPlus::ForeignKeys.config.auto_index = true
|
525
|
-
add_column(:state, :integer) do
|
526
|
-
expect(@model).not_to have_index.on(:state)
|
527
|
-
end
|
528
|
-
SchemaPlus::ForeignKeys.config.auto_index = false
|
529
|
-
end
|
530
|
-
|
531
|
-
# MySQL creates an index on foreign key and we can't override that
|
532
|
-
it "should allow to overwrite auto_index options in column definition", :mysql => :skip do
|
533
|
-
SchemaPlus::ForeignKeys.config.auto_index = true
|
534
|
-
add_column(:post_id, :integer, :index => false) do
|
535
|
-
expect(@model).not_to have_index.on(:post_id)
|
536
|
-
end
|
537
|
-
SchemaPlus::ForeignKeys.config.auto_index = false
|
538
|
-
end
|
539
|
-
|
540
|
-
it "should use default on_update action" do
|
541
|
-
SchemaPlus::ForeignKeys.config.on_update = :cascade
|
542
|
-
add_column(:post_id, :integer) do
|
543
|
-
expect(@model).to reference.on(:post_id).on_update(:cascade)
|
544
|
-
end
|
545
|
-
SchemaPlus::ForeignKeys.config.on_update = nil
|
546
|
-
end
|
547
|
-
|
548
|
-
it "should use default on_delete action" do
|
549
|
-
SchemaPlus::ForeignKeys.config.on_delete = :cascade
|
550
|
-
add_column(:post_id, :integer) do
|
551
|
-
expect(@model).to reference.on(:post_id).on_delete(:cascade)
|
552
|
-
end
|
553
|
-
SchemaPlus::ForeignKeys.config.on_delete = nil
|
554
|
-
end
|
555
|
-
|
556
|
-
it "should allow to overwrite default actions" do
|
557
|
-
SchemaPlus::ForeignKeys.config.on_delete = :cascade
|
558
|
-
SchemaPlus::ForeignKeys.config.on_update = :restrict
|
559
|
-
add_column(:post_id, :integer, :foreign_key => { :on_update => :nullify, :on_delete => :nullify}) do
|
560
|
-
expect(@model).to reference.on(:post_id).on_delete(:nullify).on_update(:nullify)
|
561
|
-
end
|
562
|
-
SchemaPlus::ForeignKeys.config.on_delete = nil
|
563
|
-
end
|
564
|
-
|
565
|
-
it "should create foreign key with default name" do
|
566
|
-
add_column(:post_id, :integer) do
|
567
|
-
expect(@model).to reference(:posts, :id).with_name("fk_#{@model.table_name}_post_id")
|
568
|
-
end
|
569
|
-
end
|
570
|
-
|
571
|
-
protected
|
572
|
-
def add_column(column_name, *args)
|
573
|
-
table = @model.table_name
|
574
|
-
ActiveRecord::Migration.suppress_messages do
|
575
|
-
ActiveRecord::Migration.add_column(table, column_name, *args)
|
576
|
-
@model.reset_column_information
|
577
|
-
yield if block_given?
|
578
|
-
ActiveRecord::Migration.remove_column(table, column_name)
|
579
|
-
end
|
580
|
-
end
|
581
|
-
|
582
|
-
end
|
583
|
-
|
584
|
-
|
585
|
-
context "when column is changed" do
|
586
|
-
|
587
|
-
before(:each) do
|
588
|
-
@model = Comment
|
589
|
-
end
|
590
|
-
|
591
|
-
context "with foreign keys", :sqlite3 => :skip do
|
592
|
-
|
593
|
-
it "should create foreign key" do
|
594
|
-
change_column :user, :string, :foreign_key => { :references => [:users, :login] }
|
595
|
-
expect(@model).to reference(:users, :login).on(:user)
|
596
|
-
end
|
597
|
-
|
598
|
-
context "and initially references to users table" do
|
599
|
-
|
600
|
-
before(:each) do
|
601
|
-
recreate_table @model do |t|
|
602
|
-
t.integer :user_id
|
603
|
-
end
|
604
|
-
end
|
605
|
-
|
606
|
-
it "should have foreign key" do
|
607
|
-
expect(@model).to reference(:users)
|
608
|
-
end
|
609
|
-
|
610
|
-
it "should drop foreign key if it is no longer valid" do
|
611
|
-
change_column :user_id, :integer, :foreign_key => { :references => :members }
|
612
|
-
expect(@model).not_to reference(:users)
|
613
|
-
end
|
614
|
-
|
615
|
-
it "should drop foreign key if requested to do so" do
|
616
|
-
change_column :user_id, :integer, :foreign_key => { :references => nil }
|
617
|
-
expect(@model).not_to reference(:users)
|
618
|
-
end
|
619
|
-
|
620
|
-
it "should remove auto-created index if foreign key is removed" do
|
621
|
-
expect(@model).to have_index.on(:user_id) # sanity check that index was auto-created
|
622
|
-
change_column :user_id, :integer, :foreign_key => { :references => nil }
|
623
|
-
expect(@model).not_to have_index.on(:user_id)
|
624
|
-
end
|
625
|
-
|
626
|
-
it "should reference pointed table afterwards if new one is created" do
|
627
|
-
change_column :user_id, :integer, :foreign_key => { :references => :members }
|
628
|
-
expect(@model).to reference(:members)
|
629
|
-
end
|
630
|
-
|
631
|
-
it "should maintain foreign key if it's unaffected by change" do
|
632
|
-
change_column :user_id, :integer, :default => 0
|
633
|
-
expect(@model).to reference(:users)
|
634
|
-
end
|
635
|
-
|
636
|
-
it "should maintain foreign key if it's unaffected by change, even if auto_index is off" do
|
637
|
-
with_fk_config(:auto_create => false) do
|
638
|
-
change_column :user_id, :integer, :default => 0
|
639
|
-
expect(@model).to reference(:users)
|
640
|
-
end
|
641
|
-
end
|
642
|
-
|
643
|
-
end
|
644
|
-
|
645
|
-
context "if column defined without foreign key but with index" do
|
646
|
-
before(:each) do
|
647
|
-
recreate_table @model do |t|
|
648
|
-
t.integer :user_id, :foreign_key => false, :index => true
|
649
|
-
end
|
650
|
-
end
|
651
|
-
|
652
|
-
it "should create the index" do
|
653
|
-
expect(@model).to have_index.on(:user_id)
|
654
|
-
end
|
655
|
-
|
656
|
-
it "adding foreign key should not fail due to attempt to auto-create existing index" do
|
657
|
-
expect { change_column :user_id, :integer, :foreign_key => true }.to_not raise_error
|
658
|
-
end
|
659
|
-
end
|
660
|
-
end
|
661
|
-
|
662
|
-
context "without foreign keys" do
|
663
|
-
|
664
|
-
it "doesn't auto-add foreign keys" do
|
665
|
-
recreate_table @model do |t|
|
666
|
-
t.integer :user_id, :foreign_key => false
|
667
|
-
t.string :other_column
|
668
|
-
end
|
669
|
-
with_fk_auto_create do
|
670
|
-
change_column :other_column, :text
|
671
|
-
end
|
672
|
-
expect(@model).to_not reference(:users)
|
673
|
-
end
|
674
|
-
|
675
|
-
end
|
676
|
-
|
677
|
-
protected
|
678
|
-
def change_column(column_name, *args)
|
679
|
-
table = @model.table_name
|
680
|
-
ActiveRecord::Migration.suppress_messages do
|
681
|
-
ActiveRecord::Migration.change_column(table, column_name, *args)
|
682
|
-
@model.reset_column_information
|
683
|
-
end
|
684
|
-
end
|
685
|
-
|
686
|
-
end
|
687
|
-
|
688
|
-
context "when column is removed", :sqlite3 => :skip do
|
689
|
-
before(:each) do
|
690
|
-
@model = Comment
|
691
|
-
recreate_table @model do |t|
|
692
|
-
t.integer :post_id
|
693
|
-
end
|
694
|
-
end
|
695
|
-
|
696
|
-
it "should remove a foreign key" do
|
697
|
-
expect(@model).to reference(:posts)
|
698
|
-
remove_column(:post_id)
|
699
|
-
expect(@model).not_to reference(:posts)
|
700
|
-
end
|
701
|
-
|
702
|
-
it "should remove an index" do
|
703
|
-
expect(@model).to have_index.on(:post_id)
|
704
|
-
remove_column(:post_id)
|
705
|
-
expect(@model).not_to have_index.on(:post_id)
|
706
|
-
end
|
707
|
-
|
708
|
-
protected
|
709
|
-
def remove_column(column_name)
|
710
|
-
table = @model.table_name
|
711
|
-
ActiveRecord::Migration.suppress_messages do
|
712
|
-
ActiveRecord::Migration.remove_column(table, column_name)
|
713
|
-
@model.reset_column_information
|
714
|
-
end
|
715
|
-
end
|
716
|
-
end
|
717
|
-
|
718
|
-
|
719
|
-
context "when table is renamed", :sqlite3 => :skip do
|
720
|
-
|
721
|
-
before(:each) do
|
722
|
-
@model = Comment
|
723
|
-
recreate_table @model do |t|
|
724
|
-
t.integer :user_id
|
725
|
-
t.integer :xyz, :index => true
|
726
|
-
end
|
727
|
-
ActiveRecord::Migration.suppress_messages do
|
728
|
-
ActiveRecord::Migration.rename_table @model.table_name, :newname
|
729
|
-
end
|
730
|
-
end
|
731
|
-
|
732
|
-
it "should rename fk indexes" do
|
733
|
-
index = ActiveRecord::Base.connection.indexes(:newname).find(&its.columns == ['user_id'])
|
734
|
-
expect(index.name).to match(/^fk__newname_/)
|
735
|
-
end
|
736
|
-
|
737
|
-
it "should rename foreign key constraints" do
|
738
|
-
expect(ActiveRecord::Base.connection.foreign_keys(:newname).first.name).to match(/newname/)
|
739
|
-
end
|
740
|
-
|
741
|
-
end
|
742
|
-
|
743
|
-
|
744
|
-
context "when table with more than one fk constraint is renamed", :sqlite3 => :skip do
|
745
|
-
|
746
|
-
before(:each) do
|
747
|
-
@model = Comment
|
748
|
-
recreate_table @model do |t|
|
749
|
-
t.integer :user_id
|
750
|
-
t.integer :member_id
|
751
|
-
end
|
752
|
-
ActiveRecord::Migration.suppress_messages do
|
753
|
-
ActiveRecord::Migration.rename_table @model.table_name, :newname
|
754
|
-
end
|
755
|
-
end
|
756
|
-
|
757
|
-
it "should rename foreign key constraints" do
|
758
|
-
names = ActiveRecord::Base.connection.foreign_keys(:newname).map(&:name)
|
759
|
-
expect(names.grep(/newname/)).to eq(names)
|
760
|
-
end
|
761
|
-
end
|
762
|
-
|
763
|
-
def recreate_table(model, opts={}, &block)
|
764
|
-
ActiveRecord::Migration.suppress_messages do
|
765
|
-
ActiveRecord::Migration.create_table model.table_name, opts.merge(:force => true), &block
|
766
|
-
end
|
767
|
-
model.reset_column_information
|
768
|
-
end
|
769
|
-
|
770
|
-
def change_table(model, opts={}, &block)
|
771
|
-
ActiveRecord::Migration.suppress_messages do
|
772
|
-
ActiveRecord::Migration.change_table model.table_name, opts, &block
|
773
|
-
end
|
774
|
-
model.reset_column_information
|
775
|
-
end
|
776
|
-
|
777
|
-
end
|
778
|
-
|