strong_migrations 0.7.9 → 1.4.4
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 +80 -0
- data/LICENSE.txt +1 -1
- data/README.md +143 -126
- data/lib/strong_migrations/adapters/abstract_adapter.rb +77 -0
- data/lib/strong_migrations/adapters/mariadb_adapter.rb +32 -0
- data/lib/strong_migrations/adapters/mysql_adapter.rb +107 -0
- data/lib/strong_migrations/adapters/postgresql_adapter.rb +230 -0
- data/lib/strong_migrations/checker.rb +115 -516
- data/lib/strong_migrations/checks.rb +460 -0
- data/lib/strong_migrations/error_messages.rb +240 -0
- data/lib/strong_migrations/migration.rb +7 -2
- data/lib/strong_migrations/migrator.rb +19 -0
- data/lib/strong_migrations/safe_methods.rb +27 -28
- data/lib/strong_migrations/schema_dumper.rb +21 -0
- data/lib/strong_migrations/version.rb +1 -1
- data/lib/strong_migrations.rb +38 -225
- data/lib/tasks/strong_migrations.rake +2 -7
- metadata +14 -7
- data/lib/strong_migrations/alphabetize_columns.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7444023bd5f0829a289ebc9d222a28f041a4e3789224438f9fd6bffa01fa6668
|
4
|
+
data.tar.gz: feb5010616cc8ef6cf36088be7a67bb0d74272cde79d0e9a0a442272bfa92d99
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '0599a3fef628ec724471ef53b7ad7358831e6b638bdd0ca3b7cb79c1b416da6c044793ecca5475f5e602e8a7d1235ced3ff3fda526f31b9c4a56990c8531f9b4'
|
7
|
+
data.tar.gz: 6aac91ecb348c6a04c25511adf7df5d3e97823f6b9acdfbfd86bac50c4f5856f15fdcc271f00d0fc6f1e5d2cfdbaf3da5e056b1476aaf9b224e7df89b9737e01
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,83 @@
|
|
1
|
+
## 1.4.4 (2023-03-08)
|
2
|
+
|
3
|
+
- Fixed `add_foreign_key` with `name` and `column` options with `safe_by_default`
|
4
|
+
|
5
|
+
## 1.4.3 (2023-02-19)
|
6
|
+
|
7
|
+
- Fixed check for `change_column` to account for charset with MySQL and MariaDB
|
8
|
+
|
9
|
+
## 1.4.2 (2023-01-29)
|
10
|
+
|
11
|
+
- Added `alphabetize_schema` option
|
12
|
+
|
13
|
+
## 1.4.1 (2023-01-05)
|
14
|
+
|
15
|
+
- Added support for multiple databases to `target_version`
|
16
|
+
|
17
|
+
## 1.4.0 (2022-10-31)
|
18
|
+
|
19
|
+
- Added check for `add_exclusion_constraint`
|
20
|
+
- Added support for `RACK_ENV`
|
21
|
+
- Fixed error when `Rails` defined without `Rails.env`
|
22
|
+
- Fixed error with `change_column_null` when table does not exist
|
23
|
+
|
24
|
+
## 1.3.2 (2022-10-09)
|
25
|
+
|
26
|
+
- Improved error message for `add_column` with `default: nil` with Postgres 10
|
27
|
+
|
28
|
+
## 1.3.1 (2022-09-21)
|
29
|
+
|
30
|
+
- Fixed check for `add_column` with `default: nil` with Postgres 10
|
31
|
+
|
32
|
+
## 1.3.0 (2022-08-30)
|
33
|
+
|
34
|
+
- Added check for `add_column` with `uuid` type and volatile default value
|
35
|
+
|
36
|
+
## 1.2.0 (2022-06-10)
|
37
|
+
|
38
|
+
- Added check for index corruption with Postgres 14.0 to 14.3
|
39
|
+
|
40
|
+
## 1.1.0 (2022-06-08)
|
41
|
+
|
42
|
+
- Added check for `force` option with `create_join_table`
|
43
|
+
- Improved errors for extra arguments
|
44
|
+
- Fixed ignoring extra arguments with `safe_by_default`
|
45
|
+
- Fixed missing options with `remove_index` and `safe_by_default`
|
46
|
+
|
47
|
+
## 1.0.0 (2022-03-21)
|
48
|
+
|
49
|
+
New safe operations with MySQL and MariaDB
|
50
|
+
|
51
|
+
- Setting `NOT NULL` on an existing column with strict mode enabled
|
52
|
+
|
53
|
+
New safe operations with Postgres
|
54
|
+
|
55
|
+
- Changing between `text` and `citext` when not indexed
|
56
|
+
- Changing a `string` column to a `citext` column when not indexed
|
57
|
+
- Changing a `citext` column to a `string` column with no `:limit` when not indexed
|
58
|
+
- Changing a `cidr` column to an `inet` column
|
59
|
+
- Increasing `:precision` of an `interval` or `time` column
|
60
|
+
|
61
|
+
New unsafe operations with Postgres
|
62
|
+
|
63
|
+
- Adding a column with a callable default value
|
64
|
+
- Decreasing `:precision` of a `datetime` column
|
65
|
+
- Decreasing `:limit` of a `timestamptz` column
|
66
|
+
- Passing a default value to `change_column_null`
|
67
|
+
|
68
|
+
Other
|
69
|
+
|
70
|
+
- Added experimental support for lock timeout retries
|
71
|
+
- Added `target_sql_mode` option
|
72
|
+
- Added error for `change_column_null` with default value with `safe_by_default` option
|
73
|
+
- Fixed instructions for `remove_columns` with options
|
74
|
+
- Dropped support for Postgres < 10, MySQL < 5.7, and MariaDB < 10.2
|
75
|
+
|
76
|
+
## 0.8.0 (2022-02-09)
|
77
|
+
|
78
|
+
- Fixed error with versioned schema with Active Record 7.0.2+
|
79
|
+
- Dropped support for Ruby < 2.6 and Active Record < 5.2
|
80
|
+
|
1
81
|
## 0.7.9 (2021-12-15)
|
2
82
|
|
3
83
|
- Fixed error with multiple databases with Active Record 7
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -4,7 +4,7 @@ Catch unsafe migrations in development
|
|
4
4
|
|
5
5
|
✓ Detects potentially dangerous operations<br /> ✓ Prevents them from running by default<br /> ✓ Provides instructions on safer ways to do what you want
|
6
6
|
|
7
|
-
Supports
|
7
|
+
Supports PostgreSQL, MySQL, and MariaDB
|
8
8
|
|
9
9
|
:tangerine: Battle-tested at [Instacart](https://www.instacart.com/opensource)
|
10
10
|
|
@@ -15,7 +15,7 @@ Supports for PostgreSQL, MySQL, and MariaDB
|
|
15
15
|
Add this line to your application’s Gemfile:
|
16
16
|
|
17
17
|
```ruby
|
18
|
-
gem
|
18
|
+
gem "strong_migrations"
|
19
19
|
```
|
20
20
|
|
21
21
|
And run:
|
@@ -67,7 +67,6 @@ Potentially dangerous operations:
|
|
67
67
|
- [renaming a table](#renaming-a-table)
|
68
68
|
- [creating a table with the force option](#creating-a-table-with-the-force-option)
|
69
69
|
- [adding a check constraint](#adding-a-check-constraint)
|
70
|
-
- [setting NOT NULL on an existing column](#setting-not-null-on-an-existing-column)
|
71
70
|
- [executing SQL directly](#executing-SQL-directly)
|
72
71
|
|
73
72
|
Postgres-specific checks:
|
@@ -75,7 +74,9 @@ Postgres-specific checks:
|
|
75
74
|
- [adding an index non-concurrently](#adding-an-index-non-concurrently)
|
76
75
|
- [adding a reference](#adding-a-reference)
|
77
76
|
- [adding a foreign key](#adding-a-foreign-key)
|
77
|
+
- [adding an exclusion constraint](#adding-an-exclusion-constraint)
|
78
78
|
- [adding a json column](#adding-a-json-column)
|
79
|
+
- [setting NOT NULL on an existing column](#setting-not-null-on-an-existing-column)
|
79
80
|
|
80
81
|
Best practices:
|
81
82
|
|
@@ -107,7 +108,7 @@ end
|
|
107
108
|
end
|
108
109
|
```
|
109
110
|
|
110
|
-
2. Deploy code
|
111
|
+
2. Deploy the code
|
111
112
|
3. Write a migration to remove the column (wrap in `safety_assured` block)
|
112
113
|
|
113
114
|
```ruby
|
@@ -118,7 +119,8 @@ end
|
|
118
119
|
end
|
119
120
|
```
|
120
121
|
|
121
|
-
4. Deploy and run migration
|
122
|
+
4. Deploy and run the migration
|
123
|
+
5. Remove the line added in step 1
|
122
124
|
|
123
125
|
### Adding a column with a default value
|
124
126
|
|
@@ -134,7 +136,7 @@ class AddSomeColumnToUsers < ActiveRecord::Migration[7.0]
|
|
134
136
|
end
|
135
137
|
```
|
136
138
|
|
137
|
-
In Postgres 11+, MySQL 8.0.12+, and MariaDB 10.3.2+, this no longer requires a table rewrite and is safe.
|
139
|
+
In Postgres 11+, MySQL 8.0.12+, and MariaDB 10.3.2+, this no longer requires a table rewrite and is safe (except for volatile functions like `gen_random_uuid()`).
|
138
140
|
|
139
141
|
#### Good
|
140
142
|
|
@@ -203,19 +205,26 @@ class ChangeSomeColumnType < ActiveRecord::Migration[7.0]
|
|
203
205
|
end
|
204
206
|
```
|
205
207
|
|
206
|
-
|
208
|
+
Some changes don’t require a table rewrite and are safe in Postgres:
|
207
209
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
210
|
+
Type | Safe Changes
|
211
|
+
--- | ---
|
212
|
+
`cidr` | Changing to `inet`
|
213
|
+
`citext` | Changing to `text` if not indexed, changing to `string` with no `:limit` if not indexed
|
214
|
+
`datetime` | Increasing or removing `:precision`, changing to `timestamptz` when session time zone is UTC in Postgres 12+
|
215
|
+
`decimal` | Increasing `:precision` at same `:scale`, removing `:precision` and `:scale`
|
216
|
+
`interval` | Increasing or removing `:precision`
|
217
|
+
`numeric` | Increasing `:precision` at same `:scale`, removing `:precision` and `:scale`
|
218
|
+
`string` | Increasing or removing `:limit`, changing to `text`, changing `citext` if not indexed
|
219
|
+
`text` | Changing to `string` with no `:limit`, changing to `citext` if not indexed
|
220
|
+
`time` | Increasing or removing `:precision`
|
221
|
+
`timestamptz` | Increasing or removing `:limit`, changing to `datetime` when session time zone is UTC in Postgres 12+
|
214
222
|
|
215
|
-
And
|
223
|
+
And some in MySQL and MariaDB:
|
216
224
|
|
217
|
-
|
218
|
-
|
225
|
+
Type | Safe Changes
|
226
|
+
--- | ---
|
227
|
+
`string` | Increasing `:limit` from under 63 up to 63, increasing `:limit` from over 63 to the max (the threshold can be different if using an encoding other than `utf8mb4` - for instance, it’s 85 for `utf8mb3` and 255 for `latin1`)
|
219
228
|
|
220
229
|
#### Good
|
221
230
|
|
@@ -352,86 +361,6 @@ end
|
|
352
361
|
|
353
362
|
[Let us know](https://github.com/ankane/strong_migrations/issues/new) if you have a safe way to do this (check constraints can be added with `NOT ENFORCED`, but enforcing blocks writes).
|
354
363
|
|
355
|
-
### Setting NOT NULL on an existing column
|
356
|
-
|
357
|
-
:turtle: Safe by default available
|
358
|
-
|
359
|
-
#### Bad
|
360
|
-
|
361
|
-
Setting `NOT NULL` on an existing column blocks reads and writes while every row is checked.
|
362
|
-
|
363
|
-
```ruby
|
364
|
-
class SetSomeColumnNotNull < ActiveRecord::Migration[7.0]
|
365
|
-
def change
|
366
|
-
change_column_null :users, :some_column, false
|
367
|
-
end
|
368
|
-
end
|
369
|
-
```
|
370
|
-
|
371
|
-
#### Good - Postgres
|
372
|
-
|
373
|
-
Instead, add a check constraint.
|
374
|
-
|
375
|
-
For Rails 6.1, use:
|
376
|
-
|
377
|
-
```ruby
|
378
|
-
class SetSomeColumnNotNull < ActiveRecord::Migration[7.0]
|
379
|
-
def change
|
380
|
-
add_check_constraint :users, "some_column IS NOT NULL", name: "users_some_column_null", validate: false
|
381
|
-
end
|
382
|
-
end
|
383
|
-
```
|
384
|
-
|
385
|
-
For Rails < 6.1, use:
|
386
|
-
|
387
|
-
```ruby
|
388
|
-
class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
|
389
|
-
def change
|
390
|
-
safety_assured do
|
391
|
-
execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
|
392
|
-
end
|
393
|
-
end
|
394
|
-
end
|
395
|
-
```
|
396
|
-
|
397
|
-
Then validate it in a separate migration. A `NOT NULL` check constraint is [functionally equivalent](https://medium.com/doctolib/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c) to setting `NOT NULL` on the column (but it won’t show up in `schema.rb` in Rails < 6.1). In Postgres 12+, once the check constraint is validated, you can safely set `NOT NULL` on the column and drop the check constraint.
|
398
|
-
|
399
|
-
For Rails 6.1, use:
|
400
|
-
|
401
|
-
```ruby
|
402
|
-
class ValidateSomeColumnNotNull < ActiveRecord::Migration[7.0]
|
403
|
-
def change
|
404
|
-
validate_check_constraint :users, name: "users_some_column_null"
|
405
|
-
|
406
|
-
# in Postgres 12+, you can then safely set NOT NULL on the column
|
407
|
-
change_column_null :users, :some_column, false
|
408
|
-
remove_check_constraint :users, name: "users_some_column_null"
|
409
|
-
end
|
410
|
-
end
|
411
|
-
```
|
412
|
-
|
413
|
-
For Rails < 6.1, use:
|
414
|
-
|
415
|
-
```ruby
|
416
|
-
class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
|
417
|
-
def change
|
418
|
-
safety_assured do
|
419
|
-
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
|
420
|
-
end
|
421
|
-
|
422
|
-
# in Postgres 12+, you can then safely set NOT NULL on the column
|
423
|
-
change_column_null :users, :some_column, false
|
424
|
-
safety_assured do
|
425
|
-
execute 'ALTER TABLE "users" DROP CONSTRAINT "users_some_column_null"'
|
426
|
-
end
|
427
|
-
end
|
428
|
-
end
|
429
|
-
```
|
430
|
-
|
431
|
-
#### Good - MySQL and MariaDB
|
432
|
-
|
433
|
-
[Let us know](https://github.com/ankane/strong_migrations/issues/new) if you have a safe way to do this.
|
434
|
-
|
435
364
|
### Executing SQL directly
|
436
365
|
|
437
366
|
Strong Migrations can’t ensure safety for raw SQL statements. Make really sure that what you’re doing is safe, then use:
|
@@ -540,9 +469,7 @@ end
|
|
540
469
|
|
541
470
|
#### Good
|
542
471
|
|
543
|
-
Add the foreign key without validating existing rows
|
544
|
-
|
545
|
-
For Rails 5.2+, use:
|
472
|
+
Add the foreign key without validating existing rows:
|
546
473
|
|
547
474
|
```ruby
|
548
475
|
class AddForeignKeyOnUsers < ActiveRecord::Migration[7.0]
|
@@ -552,7 +479,7 @@ class AddForeignKeyOnUsers < ActiveRecord::Migration[7.0]
|
|
552
479
|
end
|
553
480
|
```
|
554
481
|
|
555
|
-
Then
|
482
|
+
Then validate them in a separate migration.
|
556
483
|
|
557
484
|
```ruby
|
558
485
|
class ValidateForeignKeyOnUsers < ActiveRecord::Migration[7.0]
|
@@ -562,30 +489,24 @@ class ValidateForeignKeyOnUsers < ActiveRecord::Migration[7.0]
|
|
562
489
|
end
|
563
490
|
```
|
564
491
|
|
565
|
-
|
492
|
+
### Adding an exclusion constraint
|
566
493
|
|
567
|
-
|
568
|
-
class AddForeignKeyOnUsers < ActiveRecord::Migration[5.1]
|
569
|
-
def change
|
570
|
-
safety_assured do
|
571
|
-
execute 'ALTER TABLE "users" ADD CONSTRAINT "fk_rails_c1e9b98e31" FOREIGN KEY ("order_id") REFERENCES "orders" ("id") NOT VALID'
|
572
|
-
end
|
573
|
-
end
|
574
|
-
end
|
575
|
-
```
|
494
|
+
#### Bad
|
576
495
|
|
577
|
-
|
496
|
+
In Postgres, adding an exclusion constraint blocks reads and writes while every row is checked.
|
578
497
|
|
579
498
|
```ruby
|
580
|
-
class
|
499
|
+
class AddExclusionContraint < ActiveRecord::Migration[7.1]
|
581
500
|
def change
|
582
|
-
|
583
|
-
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "fk_rails_c1e9b98e31"'
|
584
|
-
end
|
501
|
+
add_exclusion_constraint :users, "number WITH =", using: :gist
|
585
502
|
end
|
586
503
|
end
|
587
504
|
```
|
588
505
|
|
506
|
+
#### Good
|
507
|
+
|
508
|
+
[Let us know](https://github.com/ankane/strong_migrations/issues/new) if you have a safe way to do this (exclusion constraints cannot be marked `NOT VALID`).
|
509
|
+
|
589
510
|
### Adding a json column
|
590
511
|
|
591
512
|
#### Bad
|
@@ -612,6 +533,82 @@ class AddPropertiesToUsers < ActiveRecord::Migration[7.0]
|
|
612
533
|
end
|
613
534
|
```
|
614
535
|
|
536
|
+
### Setting NOT NULL on an existing column
|
537
|
+
|
538
|
+
:turtle: Safe by default available
|
539
|
+
|
540
|
+
#### Bad
|
541
|
+
|
542
|
+
In Postgres, setting `NOT NULL` on an existing column blocks reads and writes while every row is checked.
|
543
|
+
|
544
|
+
```ruby
|
545
|
+
class SetSomeColumnNotNull < ActiveRecord::Migration[7.0]
|
546
|
+
def change
|
547
|
+
change_column_null :users, :some_column, false
|
548
|
+
end
|
549
|
+
end
|
550
|
+
```
|
551
|
+
|
552
|
+
#### Good
|
553
|
+
|
554
|
+
Instead, add a check constraint.
|
555
|
+
|
556
|
+
For Rails 6.1, use:
|
557
|
+
|
558
|
+
```ruby
|
559
|
+
class SetSomeColumnNotNull < ActiveRecord::Migration[7.0]
|
560
|
+
def change
|
561
|
+
add_check_constraint :users, "some_column IS NOT NULL", name: "users_some_column_null", validate: false
|
562
|
+
end
|
563
|
+
end
|
564
|
+
```
|
565
|
+
|
566
|
+
For Rails < 6.1, use:
|
567
|
+
|
568
|
+
```ruby
|
569
|
+
class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
|
570
|
+
def change
|
571
|
+
safety_assured do
|
572
|
+
execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
```
|
577
|
+
|
578
|
+
Then validate it in a separate migration. A `NOT NULL` check constraint is [functionally equivalent](https://medium.com/doctolib/adding-a-not-null-constraint-on-pg-faster-with-minimal-locking-38b2c00c4d1c) to setting `NOT NULL` on the column (but it won’t show up in `schema.rb` in Rails < 6.1). In Postgres 12+, once the check constraint is validated, you can safely set `NOT NULL` on the column and drop the check constraint.
|
579
|
+
|
580
|
+
For Rails 6.1, use:
|
581
|
+
|
582
|
+
```ruby
|
583
|
+
class ValidateSomeColumnNotNull < ActiveRecord::Migration[7.0]
|
584
|
+
def change
|
585
|
+
validate_check_constraint :users, name: "users_some_column_null"
|
586
|
+
|
587
|
+
# in Postgres 12+, you can then safely set NOT NULL on the column
|
588
|
+
change_column_null :users, :some_column, false
|
589
|
+
remove_check_constraint :users, name: "users_some_column_null"
|
590
|
+
end
|
591
|
+
end
|
592
|
+
```
|
593
|
+
|
594
|
+
For Rails < 6.1, use:
|
595
|
+
|
596
|
+
```ruby
|
597
|
+
class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
|
598
|
+
def change
|
599
|
+
safety_assured do
|
600
|
+
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
|
601
|
+
end
|
602
|
+
|
603
|
+
# in Postgres 12+, you can then safely set NOT NULL on the column
|
604
|
+
change_column_null :users, :some_column, false
|
605
|
+
safety_assured do
|
606
|
+
execute 'ALTER TABLE "users" DROP CONSTRAINT "users_some_column_null"'
|
607
|
+
end
|
608
|
+
end
|
609
|
+
end
|
610
|
+
```
|
611
|
+
|
615
612
|
### Keeping non-unique indexes to three columns or less
|
616
613
|
|
617
614
|
#### Bad
|
@@ -703,7 +700,7 @@ Disable specific checks with:
|
|
703
700
|
StrongMigrations.disable_check(:add_index)
|
704
701
|
```
|
705
702
|
|
706
|
-
Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations.rb) for the list of keys.
|
703
|
+
Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations/error_messages.rb) for the list of keys.
|
707
704
|
|
708
705
|
## Down Migrations / Rollbacks
|
709
706
|
|
@@ -721,7 +718,7 @@ To customize specific messages, create an initializer with:
|
|
721
718
|
StrongMigrations.error_messages[:add_column_default] = "Your custom instructions"
|
722
719
|
```
|
723
720
|
|
724
|
-
Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations.rb) for the list of keys.
|
721
|
+
Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations/error_messages.rb) for the list of keys.
|
725
722
|
|
726
723
|
## Migration Timeouts
|
727
724
|
|
@@ -743,6 +740,25 @@ ALTER ROLE myuser SET statement_timeout = '1h';
|
|
743
740
|
|
744
741
|
Note: If you use PgBouncer in transaction mode, you must set timeouts on the database user.
|
745
742
|
|
743
|
+
## Lock Timeout Retries [experimental]
|
744
|
+
|
745
|
+
There’s the option to automatically retry statements when the lock timeout is reached. Here’s how it works:
|
746
|
+
|
747
|
+
- If a lock timeout happens outside a transaction, the statement is retried
|
748
|
+
- If it happens inside the DDL transaction, the entire migration is retried (only applicable to Postgres)
|
749
|
+
|
750
|
+
Add to `config/initializers/strong_migrations.rb`:
|
751
|
+
|
752
|
+
```ruby
|
753
|
+
StrongMigrations.lock_timeout_retries = 3
|
754
|
+
```
|
755
|
+
|
756
|
+
Set the delay between retries with:
|
757
|
+
|
758
|
+
```ruby
|
759
|
+
StrongMigrations.lock_timeout_retry_delay = 10.seconds
|
760
|
+
```
|
761
|
+
|
746
762
|
## App Timeouts
|
747
763
|
|
748
764
|
We recommend adding timeouts to `config/database.yml` to prevent connections from hanging and individual queries from taking up too many resources in controllers, jobs, the Rails console, and other places.
|
@@ -808,6 +824,12 @@ The major version works well for Postgres, while the full version is recommended
|
|
808
824
|
|
809
825
|
For safety, this option only affects development and test environments. In other environments, the actual server version is always used.
|
810
826
|
|
827
|
+
If your app has multiple databases with different versions, with Rails 6.1+, you can use:
|
828
|
+
|
829
|
+
```ruby
|
830
|
+
StrongMigrations.target_version = {primary: 13, catalog: 15}
|
831
|
+
```
|
832
|
+
|
811
833
|
## Analyze Tables
|
812
834
|
|
813
835
|
Analyze tables automatically (to update planner statistics) after an index is added. Create an initializer with:
|
@@ -818,23 +840,18 @@ StrongMigrations.auto_analyze = true
|
|
818
840
|
|
819
841
|
## Faster Migrations
|
820
842
|
|
821
|
-
Only dump the schema when adding a new migration. If you use Git, add to
|
843
|
+
Only dump the schema when adding a new migration. If you use Git, add to `config/environments/development.rb`:
|
822
844
|
|
823
845
|
```rb
|
824
|
-
|
825
|
-
ActiveRecord::Base.dump_schema_after_migration = Rails.env.development? &&
|
826
|
-
`git status db/migrate/ --porcelain`.present?
|
827
|
-
end
|
828
|
-
|
829
|
-
task "db:migrate": "faster_migrations"
|
846
|
+
config.active_record.dump_schema_after_migration = `git status db/migrate/ --porcelain`.present?
|
830
847
|
```
|
831
848
|
|
832
849
|
## Schema Sanity
|
833
850
|
|
834
|
-
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
|
851
|
+
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 `config/initializers/strong_migrations.rb`:
|
835
852
|
|
836
853
|
```ruby
|
837
|
-
|
854
|
+
StrongMigrations.alphabetize_schema = true
|
838
855
|
```
|
839
856
|
|
840
857
|
## Permissions
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module StrongMigrations
|
2
|
+
module Adapters
|
3
|
+
class AbstractAdapter
|
4
|
+
def initialize(checker)
|
5
|
+
@checker = checker
|
6
|
+
end
|
7
|
+
|
8
|
+
def name
|
9
|
+
"Unknown"
|
10
|
+
end
|
11
|
+
|
12
|
+
def min_version
|
13
|
+
end
|
14
|
+
|
15
|
+
def set_statement_timeout(timeout)
|
16
|
+
raise StrongMigrations::Error, "Statement timeout not supported for this database"
|
17
|
+
end
|
18
|
+
|
19
|
+
def set_lock_timeout(timeout)
|
20
|
+
raise StrongMigrations::Error, "Lock timeout not supported for this database"
|
21
|
+
end
|
22
|
+
|
23
|
+
def check_lock_timeout(limit)
|
24
|
+
# do nothing
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_column_default_safe?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def change_type_safe?(table, column, type, options, existing_column, existing_type)
|
32
|
+
false
|
33
|
+
end
|
34
|
+
|
35
|
+
def rewrite_blocks
|
36
|
+
"reads and writes"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def connection
|
42
|
+
@checker.send(:connection)
|
43
|
+
end
|
44
|
+
|
45
|
+
def select_all(statement)
|
46
|
+
connection.select_all(statement)
|
47
|
+
end
|
48
|
+
|
49
|
+
def target_version(target_version)
|
50
|
+
target_version ||= StrongMigrations.target_version
|
51
|
+
version =
|
52
|
+
if target_version && StrongMigrations.developer_env?
|
53
|
+
if target_version.is_a?(Hash)
|
54
|
+
# Active Record 6.0 supports multiple databases
|
55
|
+
# but connection.pool.spec.name always returns "primary"
|
56
|
+
# in migrations with rails db:migrate
|
57
|
+
if ActiveRecord::VERSION::STRING.to_f < 6.1
|
58
|
+
# error class is not shown in db:migrate output so ensure message is descriptive
|
59
|
+
raise StrongMigrations::Error, "StrongMigrations.target_version does not support multiple databases for Active Record < 6.1"
|
60
|
+
end
|
61
|
+
|
62
|
+
db_config_name = connection.pool.db_config.name
|
63
|
+
target_version.stringify_keys.fetch(db_config_name) do
|
64
|
+
# error class is not shown in db:migrate output so ensure message is descriptive
|
65
|
+
raise StrongMigrations::Error, "StrongMigrations.target_version is not configured for :#{db_config_name} database"
|
66
|
+
end.to_s
|
67
|
+
else
|
68
|
+
target_version.to_s
|
69
|
+
end
|
70
|
+
else
|
71
|
+
yield
|
72
|
+
end
|
73
|
+
Gem::Version.new(version)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module StrongMigrations
|
2
|
+
module Adapters
|
3
|
+
class MariaDBAdapter < MySQLAdapter
|
4
|
+
def name
|
5
|
+
"MariaDB"
|
6
|
+
end
|
7
|
+
|
8
|
+
def min_version
|
9
|
+
"10.2"
|
10
|
+
end
|
11
|
+
|
12
|
+
def server_version
|
13
|
+
@server_version ||= begin
|
14
|
+
target_version(StrongMigrations.target_mariadb_version) do
|
15
|
+
select_all("SELECT VERSION()").first["VERSION()"].split("-").first
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def set_statement_timeout(timeout)
|
21
|
+
# fix deprecation warning with Active Record 7.1
|
22
|
+
timeout = timeout.value if timeout.is_a?(ActiveSupport::Duration)
|
23
|
+
|
24
|
+
select_all("SET max_statement_time = #{connection.quote(timeout)}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_column_default_safe?
|
28
|
+
server_version >= Gem::Version.new("10.3.2")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|