strong_migrations 0.4.2 → 0.5.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/CHANGELOG.md +25 -19
- data/README.md +112 -14
- data/lib/strong_migrations.rb +51 -5
- data/lib/strong_migrations/checker.rb +33 -14
- data/lib/strong_migrations/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 372efa1cc2267462dd7294cf7d39cd710941b223df3d38ec4d24fd7a91feb7ad
|
4
|
+
data.tar.gz: '0139953c4aee0b08a15e9169af644eca36aa3ecd49d5c7c23a678d7423c35233'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1d8049950bb0a8d38d01479b5a00e6ca9ed80878d2a7b8d21a8217efaf51e7727793d82845c9287c4e18619aa4a36d581b69de47e8ab48f16612ebf9188601c
|
7
|
+
data.tar.gz: 7b9f3a70ec40ffa42fe8e2928998de861cca4bcbdb23ad3ad9134b4fea09cc0228439b32cb8ec19910d5faf6f331445ba692bca1b8d0a5681d1d77df78554374
|
data/CHANGELOG.md
CHANGED
@@ -1,93 +1,99 @@
|
|
1
|
-
## 0.
|
1
|
+
## 0.5.0 (2019-12-05)
|
2
|
+
|
3
|
+
- Added ability to disable checks
|
4
|
+
- Added Postgres-specific check for `change_column_null`
|
5
|
+
- Added optional remove index check
|
6
|
+
|
7
|
+
## 0.4.2 (2019-10-27)
|
2
8
|
|
3
9
|
- Allow `add_reference` with concurrent indexes
|
4
10
|
|
5
|
-
## 0.4.1
|
11
|
+
## 0.4.1 (2019-07-12)
|
6
12
|
|
7
13
|
- Added `target_postgresql_version`
|
8
14
|
- Added `unscoped` to backfill instructions
|
9
15
|
|
10
|
-
## 0.4.0
|
16
|
+
## 0.4.0 (2019-05-27)
|
11
17
|
|
12
18
|
- Added check for `add_foreign_key`
|
13
19
|
- Fixed instructions for adding default value with NOT NULL constraint
|
14
20
|
- Removed support for Rails 4.2
|
15
21
|
|
16
|
-
## 0.3.1
|
22
|
+
## 0.3.1 (2018-10-18)
|
17
23
|
|
18
24
|
- Fixed error with `remove_column` and `type` argument
|
19
25
|
- Improved message customization
|
20
26
|
|
21
|
-
## 0.3.0
|
27
|
+
## 0.3.0 (2018-10-15)
|
22
28
|
|
23
29
|
- Added support for custom checks
|
24
30
|
- Adding a column with a non-null default value is safe in Postgres 11+
|
25
31
|
- Added checks for `add_belongs_to`, `remove_belongs_to`, `remove_columns`, and `remove_reference`
|
26
32
|
- Customized messages
|
27
33
|
|
28
|
-
## 0.2.3
|
34
|
+
## 0.2.3 (2018-07-22)
|
29
35
|
|
30
36
|
- Added check for `change_column_null`
|
31
37
|
- Added support for alphabetize columns with Makara
|
32
38
|
- Fixed migration reversibility with `auto_analyze`
|
33
39
|
|
34
|
-
## 0.2.2
|
40
|
+
## 0.2.2 (2018-02-14)
|
35
41
|
|
36
42
|
- Friendlier output
|
37
43
|
- Better method of hooking into ActiveRecord
|
38
44
|
|
39
|
-
## 0.2.1
|
45
|
+
## 0.2.1 (2018-02-07)
|
40
46
|
|
41
47
|
- Recommend `disable_ddl_transaction!` over `commit_db_transaction`
|
42
48
|
- Suggest `jsonb` over `json` in Postgres 9.4+
|
43
49
|
- Changing `varchar` to `text` is safe in Postgres 9.1+
|
44
50
|
- Do not check number of columns for unique indexes
|
45
51
|
|
46
|
-
## 0.2.0
|
52
|
+
## 0.2.0 (2018-01-07)
|
47
53
|
|
48
54
|
- Added customizable error messages
|
49
55
|
- Updated instructions for adding a column with a default value
|
50
56
|
|
51
|
-
## 0.1.9
|
57
|
+
## 0.1.9 (2017-06-14)
|
52
58
|
|
53
59
|
- Added `start_after` option
|
54
60
|
|
55
|
-
## 0.1.8
|
61
|
+
## 0.1.8 (2017-05-31)
|
56
62
|
|
57
63
|
- Fixed error with `create_table`
|
58
64
|
- Added check for executing arbitrary SQL
|
59
65
|
|
60
|
-
## 0.1.7
|
66
|
+
## 0.1.7 (2017-05-29)
|
61
67
|
|
62
68
|
- Added check for `force` option with `create_table`
|
63
69
|
- Added `auto_analyze` option
|
64
70
|
|
65
|
-
## 0.1.6
|
71
|
+
## 0.1.6 (2017-03-23)
|
66
72
|
|
67
73
|
- Adding an index to a newly created table is now safe
|
68
74
|
|
69
|
-
## 0.1.5
|
75
|
+
## 0.1.5 (2016-07-23)
|
70
76
|
|
71
77
|
- Fixed error with Ruby 2.3 frozen strings
|
72
78
|
|
73
|
-
## 0.1.4
|
79
|
+
## 0.1.4 (2016-03-22)
|
74
80
|
|
75
81
|
- Added alphabetize columns
|
76
82
|
|
77
|
-
## 0.1.3
|
83
|
+
## 0.1.3 (2016-03-12)
|
78
84
|
|
79
85
|
- Disabled dangerous rake tasks in production
|
80
86
|
- Added ability to use `SAFETY_ASSURED` env var
|
81
87
|
|
82
|
-
## 0.1.2
|
88
|
+
## 0.1.2 (2016-02-24)
|
83
89
|
|
84
90
|
- Skip checks on down migrations and rollbacks
|
85
91
|
- Added check for indexes with more than 3 columns
|
86
92
|
|
87
|
-
## 0.1.1
|
93
|
+
## 0.1.1 (2015-11-29)
|
88
94
|
|
89
95
|
- Fixed `add_index` check for MySQL
|
90
96
|
|
91
|
-
## 0.1.0
|
97
|
+
## 0.1.0 (2015-11-22)
|
92
98
|
|
93
99
|
- First release
|
data/README.md
CHANGED
@@ -34,10 +34,14 @@ The following operations can cause downtime or errors:
|
|
34
34
|
- [[+]](#renaming-or-changing-the-type-of-a-column) renaming a column
|
35
35
|
- [[+]](#renaming-a-table) renaming a table
|
36
36
|
- [[+]](#creating-a-table-with-the-force-option) creating a table with the `force` option
|
37
|
-
- [[+]](#using-change_column_null
|
37
|
+
- [[+]](#using-change_column_null) using `change_column_null`
|
38
38
|
- [[+]](#adding-a-json-column) adding a `json` column
|
39
39
|
|
40
|
-
|
40
|
+
Optional checks:
|
41
|
+
|
42
|
+
- [[+]](#removing-an-index) removing an index non-concurrently
|
43
|
+
|
44
|
+
Best practices:
|
41
45
|
|
42
46
|
- [[+]](#keeping-non-unique-indexes-to-three-columns-or-less) keeping non-unique indexes to three columns or less
|
43
47
|
|
@@ -82,6 +86,8 @@ end
|
|
82
86
|
|
83
87
|
### Adding a column with a default value
|
84
88
|
|
89
|
+
Note: This operation is safe in Postgres 11+.
|
90
|
+
|
85
91
|
#### Bad
|
86
92
|
|
87
93
|
Adding a column with a default value to an existing table causes the entire table to be rewritten.
|
@@ -94,8 +100,6 @@ class AddSomeColumnToUsers < ActiveRecord::Migration[6.0]
|
|
94
100
|
end
|
95
101
|
```
|
96
102
|
|
97
|
-
> This operation is safe in Postgres 11+
|
98
|
-
|
99
103
|
#### Good
|
100
104
|
|
101
105
|
Instead, add the column without a default value, then change the default.
|
@@ -153,7 +157,7 @@ end
|
|
153
157
|
|
154
158
|
#### Bad
|
155
159
|
|
156
|
-
In Postgres, adding
|
160
|
+
In Postgres, adding an index non-concurrently locks the table.
|
157
161
|
|
158
162
|
```ruby
|
159
163
|
class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
|
@@ -183,7 +187,7 @@ If you forget `disable_ddl_transaction!`, the migration will fail. Also, note th
|
|
183
187
|
|
184
188
|
#### Bad
|
185
189
|
|
186
|
-
Rails adds
|
190
|
+
Rails adds an index non-concurrently to references by default, which is problematic for Postgres.
|
187
191
|
|
188
192
|
```ruby
|
189
193
|
class AddReferenceToUsers < ActiveRecord::Migration[6.0]
|
@@ -207,13 +211,11 @@ class AddReferenceToUsers < ActiveRecord::Migration[6.0]
|
|
207
211
|
end
|
208
212
|
```
|
209
213
|
|
210
|
-
For polymorphic references, add a compound index on type and id.
|
211
|
-
|
212
214
|
### Adding a foreign key
|
213
215
|
|
214
216
|
#### Bad
|
215
217
|
|
216
|
-
In Postgres, new foreign keys are validated by default, which acquires
|
218
|
+
In Postgres, new foreign keys are validated by default, which acquires a `ShareRowExclusiveLock` that can be [expensive on large tables](https://travisofthenorth.com/blog/2017/2/2/postgres-adding-foreign-keys-with-zero-downtime).
|
217
219
|
|
218
220
|
```ruby
|
219
221
|
class AddForeignKeyOnUsers < ActiveRecord::Migration[6.0]
|
@@ -359,7 +361,49 @@ class CreateUsers < ActiveRecord::Migration[6.0]
|
|
359
361
|
end
|
360
362
|
```
|
361
363
|
|
362
|
-
### Using change_column_null
|
364
|
+
### Using change_column_null
|
365
|
+
|
366
|
+
#### Bad
|
367
|
+
|
368
|
+
In Postgres, setting `NOT NULL` on an existing column requires an `AccessExclusiveLock`, which is expensive on large tables.
|
369
|
+
|
370
|
+
```ruby
|
371
|
+
class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
|
372
|
+
def change
|
373
|
+
change_column_null :users, :some_column, false
|
374
|
+
end
|
375
|
+
end
|
376
|
+
```
|
377
|
+
|
378
|
+
#### Good
|
379
|
+
|
380
|
+
Instead, add a constraint:
|
381
|
+
|
382
|
+
```ruby
|
383
|
+
class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
|
384
|
+
def change
|
385
|
+
safety_assured do
|
386
|
+
execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
```
|
391
|
+
|
392
|
+
Then validate it in a separate migration.
|
393
|
+
|
394
|
+
```ruby
|
395
|
+
class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
|
396
|
+
def change
|
397
|
+
safety_assured do
|
398
|
+
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
```
|
403
|
+
|
404
|
+
Note: This is not 100% the same as `NOT NULL` column constraint. Here’s a [good explanation](https://medium.com/doctolib/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c).
|
405
|
+
|
406
|
+
### Using change_column_null with a default value (non-Postgres)
|
363
407
|
|
364
408
|
#### Bad
|
365
409
|
|
@@ -385,11 +429,13 @@ class ChangeSomeColumnNull < ActiveRecord::Migration[6.0]
|
|
385
429
|
end
|
386
430
|
```
|
387
431
|
|
432
|
+
Note: In Postgres, `change_column_null` is still [not safe](#using-change_column_null) with this method.
|
433
|
+
|
388
434
|
### Adding a json column
|
389
435
|
|
390
436
|
#### Bad
|
391
437
|
|
392
|
-
In Postgres, there’s no equality operator for the `json` column type, which
|
438
|
+
In Postgres, there’s no equality operator for the `json` column type, which can cause errors for existing `SELECT DISTINCT` queries.
|
393
439
|
|
394
440
|
```ruby
|
395
441
|
class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
|
@@ -411,6 +457,48 @@ class AddPropertiesToUsers < ActiveRecord::Migration[6.0]
|
|
411
457
|
end
|
412
458
|
```
|
413
459
|
|
460
|
+
## Optional Checks
|
461
|
+
|
462
|
+
Some operations rarely cause issues in practice, but can be checked if desired. Enable checks with:
|
463
|
+
|
464
|
+
```ruby
|
465
|
+
StrongMigrations.enable_check(:remove_index)
|
466
|
+
```
|
467
|
+
|
468
|
+
To start a check only after a specific migration, use:
|
469
|
+
|
470
|
+
```ruby
|
471
|
+
StrongMigrations.enable_check(:remove_index, start_after: 20170101000000)
|
472
|
+
```
|
473
|
+
|
474
|
+
### Removing an index
|
475
|
+
|
476
|
+
#### Bad
|
477
|
+
|
478
|
+
In Postgres, removing an index non-concurrently locks the table for a brief period.
|
479
|
+
|
480
|
+
```ruby
|
481
|
+
class RemoveSomeIndexFromUsers < ActiveRecord::Migration[6.0]
|
482
|
+
def change
|
483
|
+
remove_index :users, :some_column
|
484
|
+
end
|
485
|
+
end
|
486
|
+
```
|
487
|
+
|
488
|
+
#### Good
|
489
|
+
|
490
|
+
Remove indexes concurrently.
|
491
|
+
|
492
|
+
```ruby
|
493
|
+
class RemoveSomeIndexFromUsers < ActiveRecord::Migration[6.0]
|
494
|
+
disable_ddl_transaction!
|
495
|
+
|
496
|
+
def change
|
497
|
+
remove_index :users, column: :some_column, algorithm: :concurrently
|
498
|
+
end
|
499
|
+
end
|
500
|
+
```
|
501
|
+
|
414
502
|
## Best Practices
|
415
503
|
|
416
504
|
### Keeping non-unique indexes to three columns or less
|
@@ -439,7 +527,7 @@ class AddSomeIndexToUsers < ActiveRecord::Migration[6.0]
|
|
439
527
|
end
|
440
528
|
```
|
441
529
|
|
442
|
-
|
530
|
+
For Postgres, be sure to add them concurrently.
|
443
531
|
|
444
532
|
## Assuring Safety
|
445
533
|
|
@@ -469,7 +557,17 @@ end
|
|
469
557
|
|
470
558
|
Use the `stop!` method to stop migrations.
|
471
559
|
|
472
|
-
|
560
|
+
Note: Since `remove_column` always requires a `safety_assured` block, it’s not possible to add a custom check for `remove_column` operations.
|
561
|
+
|
562
|
+
## Disable Checks
|
563
|
+
|
564
|
+
Disable specific checks with:
|
565
|
+
|
566
|
+
```ruby
|
567
|
+
StrongMigrations.disable_check(:add_index)
|
568
|
+
```
|
569
|
+
|
570
|
+
Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations.rb) for the list of keys.
|
473
571
|
|
474
572
|
## Existing Migrations
|
475
573
|
|
@@ -500,7 +598,7 @@ ActiveRecord::Base.dump_schema_after_migration = Rails.env.development? &&
|
|
500
598
|
|
501
599
|
## Schema Sanity
|
502
600
|
|
503
|
-
Columns can flip order in `db/schema.rb` when you have multiple developers. One way to prevent this is to [alphabetize them](https://www.pgrs.net/2008/03/
|
601
|
+
Columns can flip order in `db/schema.rb` when you have multiple developers. One way to prevent this is to [alphabetize them](https://www.pgrs.net/2008/03/12/alphabetize-schema-rb-columns/). Add to the end of your `Rakefile`:
|
504
602
|
|
505
603
|
```ruby
|
506
604
|
task "db:schema:dump": "strong_migrations:alphabetize_columns"
|
data/lib/strong_migrations.rb
CHANGED
@@ -9,7 +9,7 @@ require "strong_migrations/version"
|
|
9
9
|
|
10
10
|
module StrongMigrations
|
11
11
|
class << self
|
12
|
-
attr_accessor :auto_analyze, :start_after, :checks, :error_messages, :target_postgresql_version
|
12
|
+
attr_accessor :auto_analyze, :start_after, :checks, :error_messages, :target_postgresql_version, :enabled_checks
|
13
13
|
end
|
14
14
|
self.auto_analyze = false
|
15
15
|
self.start_after = 0
|
@@ -41,8 +41,8 @@ class Backfill%{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
|
41
41
|
end%{append}",
|
42
42
|
|
43
43
|
add_column_json:
|
44
|
-
"There's no equality operator for the json column type, which
|
45
|
-
|
44
|
+
"There's no equality operator for the json column type, which can
|
45
|
+
cause errors for existing SELECT DISTINCT queries. Use jsonb instead.",
|
46
46
|
|
47
47
|
change_column:
|
48
48
|
"Changing the type of an existing column requires the entire
|
@@ -91,7 +91,7 @@ end",
|
|
91
91
|
6. Drop the old table",
|
92
92
|
|
93
93
|
add_reference:
|
94
|
-
"Adding
|
94
|
+
"Adding an index non-concurrently locks the table. Instead, use:
|
95
95
|
|
96
96
|
class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
97
97
|
disable_ddl_transaction!
|
@@ -102,7 +102,18 @@ class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
|
102
102
|
end",
|
103
103
|
|
104
104
|
add_index:
|
105
|
-
"Adding
|
105
|
+
"Adding an index non-concurrently locks the table. Instead, use:
|
106
|
+
|
107
|
+
class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
108
|
+
disable_ddl_transaction!
|
109
|
+
|
110
|
+
def change
|
111
|
+
%{command}
|
112
|
+
end
|
113
|
+
end",
|
114
|
+
|
115
|
+
remove_index:
|
116
|
+
"Removing an index non-concurrently locks the table. Instead, use:
|
106
117
|
|
107
118
|
class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
108
119
|
disable_ddl_transaction!
|
@@ -144,6 +155,23 @@ class Backfill%{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
|
144
155
|
end
|
145
156
|
end",
|
146
157
|
|
158
|
+
change_column_null_postgresql:
|
159
|
+
"Setting NOT NULL on a column requires an AccessExclusiveLock,
|
160
|
+
which is expensive on large tables. Instead, use a constraint and
|
161
|
+
validate it in a separate migration with a more agreeable RowShareLock.
|
162
|
+
|
163
|
+
class %{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
164
|
+
def change
|
165
|
+
%{add_constraint_code}
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
class Validate%{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
170
|
+
def change
|
171
|
+
%{validate_constraint_code}
|
172
|
+
end
|
173
|
+
end",
|
174
|
+
|
147
175
|
add_foreign_key:
|
148
176
|
"New foreign keys are validated by default. This acquires an AccessExclusiveLock,
|
149
177
|
which is expensive on large tables. Instead, validate it in a separate migration
|
@@ -161,10 +189,28 @@ class Validate%{migration_name} < ActiveRecord::Migration%{migration_suffix}
|
|
161
189
|
end
|
162
190
|
end",
|
163
191
|
}
|
192
|
+
self.enabled_checks = (error_messages.keys - [:remove_index]).map { |k| [k, {}] }.to_h
|
164
193
|
|
165
194
|
def self.add_check(&block)
|
166
195
|
checks << block
|
167
196
|
end
|
197
|
+
|
198
|
+
def self.enable_check(check, start_after: nil)
|
199
|
+
enabled_checks[check] = {start_after: start_after}
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.disable_check(check)
|
203
|
+
enabled_checks.delete(check)
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.check_enabled?(check, version: nil)
|
207
|
+
if enabled_checks[check]
|
208
|
+
start_after = enabled_checks[check][:start_after] || StrongMigrations.start_after
|
209
|
+
!version || version > start_after
|
210
|
+
else
|
211
|
+
false
|
212
|
+
end
|
213
|
+
end
|
168
214
|
end
|
169
215
|
|
170
216
|
ActiveSupport.on_load(:active_record) do
|
@@ -59,9 +59,19 @@ module StrongMigrations
|
|
59
59
|
if columns.is_a?(Array) && columns.size > 3 && !options[:unique]
|
60
60
|
raise_error :add_index_columns, header: "Best practice"
|
61
61
|
end
|
62
|
-
if postgresql? && options[:algorithm] != :concurrently &&
|
62
|
+
if postgresql? && options[:algorithm] != :concurrently && !new_table?(table)
|
63
63
|
raise_error :add_index, command: command_str("add_index", [table, columns, options.merge(algorithm: :concurrently)])
|
64
64
|
end
|
65
|
+
when :remove_index
|
66
|
+
table, options = args
|
67
|
+
unless options.is_a?(Hash)
|
68
|
+
options = {column: options}
|
69
|
+
end
|
70
|
+
options ||= {}
|
71
|
+
|
72
|
+
if postgresql? && options[:algorithm] != :concurrently && !new_table?(table)
|
73
|
+
raise_error :remove_index, command: command_str("remove_index", [table, options.merge(algorithm: :concurrently)])
|
74
|
+
end
|
65
75
|
when :add_column
|
66
76
|
table, column, type, options = args
|
67
77
|
options ||= {}
|
@@ -73,13 +83,7 @@ module StrongMigrations
|
|
73
83
|
options = options.except(:null)
|
74
84
|
append = "
|
75
85
|
|
76
|
-
Then add the NOT NULL constraint.
|
77
|
-
|
78
|
-
class %{migration_name}NotNull < ActiveRecord::Migration%{migration_suffix}
|
79
|
-
def change
|
80
|
-
#{command_str("change_column_null", [table, column, false])}
|
81
|
-
end
|
82
|
-
end"
|
86
|
+
Then add the NOT NULL constraint."
|
83
87
|
end
|
84
88
|
|
85
89
|
raise_error :add_column_default,
|
@@ -133,9 +137,18 @@ end"
|
|
133
137
|
raise_error :execute, header: "Possibly dangerous operation"
|
134
138
|
when :change_column_null
|
135
139
|
table, column, null, default = args
|
136
|
-
if !null
|
137
|
-
|
138
|
-
|
140
|
+
if !null
|
141
|
+
if postgresql?
|
142
|
+
# match https://github.com/nullobject/rein
|
143
|
+
constraint_name = "#{table}_#{column}_null"
|
144
|
+
|
145
|
+
raise_error :change_column_null_postgresql,
|
146
|
+
add_constraint_code: constraint_str("ALTER TABLE %s ADD CONSTRAINT %s CHECK (%s IS NOT NULL) NOT VALID", [table, constraint_name, column]),
|
147
|
+
validate_constraint_code: constraint_str("ALTER TABLE %s VALIDATE CONSTRAINT %s", [table, constraint_name])
|
148
|
+
elsif !default.nil?
|
149
|
+
raise_error :change_column_null,
|
150
|
+
code: backfill_code(table, column, default)
|
151
|
+
end
|
139
152
|
end
|
140
153
|
when :add_foreign_key
|
141
154
|
from_table, to_table, options = args
|
@@ -159,8 +172,8 @@ end"
|
|
159
172
|
fk_name = options[:name] || "fk_rails_#{hashed_identifier}"
|
160
173
|
|
161
174
|
raise_error :add_foreign_key,
|
162
|
-
add_foreign_key_code:
|
163
|
-
validate_foreign_key_code:
|
175
|
+
add_foreign_key_code: constraint_str("ALTER TABLE %s ADD CONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s (%s) NOT VALID", [from_table, fk_name, column, to_table, primary_key]),
|
176
|
+
validate_foreign_key_code: constraint_str("ALTER TABLE %s VALIDATE CONSTRAINT %s", [from_table, fk_name])
|
164
177
|
end
|
165
178
|
end
|
166
179
|
end
|
@@ -214,6 +227,8 @@ end"
|
|
214
227
|
end
|
215
228
|
|
216
229
|
def raise_error(message_key, header: nil, **vars)
|
230
|
+
return unless StrongMigrations.check_enabled?(message_key, version: version)
|
231
|
+
|
217
232
|
message = StrongMigrations.error_messages[message_key] || "Missing message"
|
218
233
|
|
219
234
|
vars[:migration_name] = self.class.name
|
@@ -229,7 +244,7 @@ end"
|
|
229
244
|
@migration.stop!(message.gsub(/%(?!{)/, "%%") % vars, header: header || "Dangerous operation detected")
|
230
245
|
end
|
231
246
|
|
232
|
-
def
|
247
|
+
def constraint_str(statement, identifiers)
|
233
248
|
# not all identifiers are tables, but this method of quoting should be fine
|
234
249
|
code = statement % identifiers.map { |v| connection.quote_table_name(v) }
|
235
250
|
"safety_assured do\n execute '#{code}' \n end"
|
@@ -262,5 +277,9 @@ end"
|
|
262
277
|
model = table.to_s.classify
|
263
278
|
"#{model}.unscoped.in_batches do |relation| \n relation.update_all #{column}: #{default.inspect}\n sleep(0.1)\n end"
|
264
279
|
end
|
280
|
+
|
281
|
+
def new_table?(table)
|
282
|
+
@new_tables.include?(table.to_s)
|
283
|
+
end
|
265
284
|
end
|
266
285
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: strong_migrations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2019-
|
13
|
+
date: 2019-12-05 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|