strong_migrations 2.0.0 → 2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c963e6ef1e6a07f02f06e4a9838738df97014adaa3892bb8a8f11de2eb640455
4
- data.tar.gz: f50bf92538e55ce8059340adc77ee4697656824b2ad2ca3f5a34a5b1ceb82bc5
3
+ metadata.gz: 971d5d1eabb91dc04c72cc99a24f8b92f1b0d31d8d28369577f48c283b8d8624
4
+ data.tar.gz: '08a413578f564ada7f9768aeaf469719ca051e4c37057be6324e593c73fb3144'
5
5
  SHA512:
6
- metadata.gz: 04e219c413e77a0ac48465b9387f780d0c15e7e18871f9dfcddb6a8fb2a1cad990d0e612b22e141fdca2da8ead445d5fe8622fcf56648d1b3ff45bcdcfd18788
7
- data.tar.gz: 95e7d2ef43b677e975f8ac1ee5ad81b165ea6e0558acbd60448addc085b1a96e39cbf37b288ffd92ae8862e2dbf53f0abb3f21de6f208b806b3c18c9d64977f0
6
+ metadata.gz: b8ca27268e166609ec8253ce686c6fe9cbe6d7c4b298f8c80ce7f1690e76a2c997fad2806cce52c9765f6ee92e7e389fdf6c830d3ca8ebb0241574adc02c4b57
7
+ data.tar.gz: 18731d2b1bdd12698d6b860a470249a24ea12aaa0b5b74b6510d41527ef2126c46b27ef4aa7c7adb1437bd7a006d0bb7c46490d24ec15720009723e5b0d8eca4
data/CHANGELOG.md CHANGED
@@ -1,3 +1,45 @@
1
+ ## 2.5.0 (2025-07-27)
2
+
3
+ - Added check for `rename_schema`
4
+ - Made `auto_analyze` apply to `add_reference`
5
+
6
+ ## 2.4.0 (2025-06-23)
7
+
8
+ - Added `remove_invalid_indexes` option to install generator
9
+ - Added experimental `transaction_timeout` option
10
+ - Dropped support for Ruby < 3.2 and Active Record < 7.1
11
+
12
+ ## 2.3.0 (2025-04-03)
13
+
14
+ - Added check for `change_column` for columns with check constraints with Postgres
15
+
16
+ ## 2.2.1 (2025-03-21)
17
+
18
+ - Added support for `change_column_null` with default value with `safe_by_default` option
19
+ - Improved backfill instructions
20
+ - Fixed `safe_by_default` applying to migrations before `start_after`
21
+
22
+ ## 2.2.0 (2025-02-01)
23
+
24
+ - Fixed constraint name for long table and column names with `change_column_null`
25
+ - Dropped support for Active Record < 7
26
+
27
+ ## 2.1.0 (2024-11-08)
28
+
29
+ - Added `skip_database` method
30
+ - Added experimental `remove_invalid_indexes` option
31
+ - Added warning for unsupported adapters
32
+ - Improved output for `db:forward`, `db:rollback`, `db:migrate:up`, and `db:migrate:down`
33
+ - Made operations more retriable with `safe_by_default`
34
+
35
+ ## 2.0.2 (2024-10-30)
36
+
37
+ - Fixed migrations not running with Active Record 8 rc2
38
+
39
+ ## 2.0.1 (2024-10-14)
40
+
41
+ - Fixed issue with `alphabetize_schema` and virtual columns
42
+
1
43
  ## 2.0.0 (2024-06-28)
2
44
 
3
45
  - Improved install generator for Trilogy
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Bob Remeika and David Waller, 2015-2024 Andrew Kane
1
+ Copyright (c) 2013 Bob Remeika and David Waller, 2015-2025 Andrew Kane
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -43,7 +43,7 @@ end
43
43
 
44
44
  Deploy the code, then wrap this step in a safety_assured { ... } block.
45
45
 
46
- class RemoveColumn < ActiveRecord::Migration[7.1]
46
+ class RemoveColumn < ActiveRecord::Migration[8.0]
47
47
  def change
48
48
  safety_assured { remove_column :users, :name }
49
49
  end
@@ -80,6 +80,7 @@ Postgres-specific checks:
80
80
  - [adding a json column](#adding-a-json-column)
81
81
  - [setting NOT NULL on an existing column](#setting-not-null-on-an-existing-column)
82
82
  - [adding a column with a volatile default value](#adding-a-column-with-a-volatile-default-value)
83
+ - [renaming a schema](#renaming-a-schema)
83
84
 
84
85
  Config-specific checks:
85
86
 
@@ -98,7 +99,7 @@ You can also add [custom checks](#custom-checks) or [disable specific checks](#d
98
99
  Active Record caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
99
100
 
100
101
  ```ruby
101
- class RemoveSomeColumnFromUsers < ActiveRecord::Migration[7.1]
102
+ class RemoveSomeColumnFromUsers < ActiveRecord::Migration[8.0]
102
103
  def change
103
104
  remove_column :users, :some_column
104
105
  end
@@ -119,7 +120,7 @@ end
119
120
  3. Write a migration to remove the column (wrap in `safety_assured` block)
120
121
 
121
122
  ```ruby
122
- class RemoveSomeColumnFromUsers < ActiveRecord::Migration[7.1]
123
+ class RemoveSomeColumnFromUsers < ActiveRecord::Migration[8.0]
123
124
  def change
124
125
  safety_assured { remove_column :users, :some_column }
125
126
  end
@@ -136,7 +137,7 @@ end
136
137
  Changing the type of a column causes the entire table to be rewritten. During this time, reads and writes are blocked in Postgres, and writes are blocked in MySQL and MariaDB.
137
138
 
138
139
  ```ruby
139
- class ChangeSomeColumnType < ActiveRecord::Migration[7.1]
140
+ class ChangeSomeColumnType < ActiveRecord::Migration[8.0]
140
141
  def change
141
142
  change_column :users, :some_column, :new_type
142
143
  end
@@ -182,7 +183,7 @@ A safer approach is to:
182
183
  Renaming a column that’s in use will cause errors in your application.
183
184
 
184
185
  ```ruby
185
- class RenameSomeColumn < ActiveRecord::Migration[7.1]
186
+ class RenameSomeColumn < ActiveRecord::Migration[8.0]
186
187
  def change
187
188
  rename_column :users, :some_column, :new_name
188
189
  end
@@ -207,7 +208,7 @@ A safer approach is to:
207
208
  Renaming a table that’s in use will cause errors in your application.
208
209
 
209
210
  ```ruby
210
- class RenameUsersToCustomers < ActiveRecord::Migration[7.1]
211
+ class RenameUsersToCustomers < ActiveRecord::Migration[8.0]
211
212
  def change
212
213
  rename_table :users, :customers
213
214
  end
@@ -232,7 +233,7 @@ A safer approach is to:
232
233
  The `force` option can drop an existing table.
233
234
 
234
235
  ```ruby
235
- class CreateUsers < ActiveRecord::Migration[7.1]
236
+ class CreateUsers < ActiveRecord::Migration[8.0]
236
237
  def change
237
238
  create_table :users, force: true do |t|
238
239
  # ...
@@ -246,7 +247,7 @@ end
246
247
  Create tables without the `force` option.
247
248
 
248
249
  ```ruby
249
- class CreateUsers < ActiveRecord::Migration[7.1]
250
+ class CreateUsers < ActiveRecord::Migration[8.0]
250
251
  def change
251
252
  create_table :users do |t|
252
253
  # ...
@@ -264,7 +265,7 @@ If you intend to drop an existing table, run `drop_table` first.
264
265
  Adding an auto-incrementing column (`serial`/`bigserial` in Postgres and `AUTO_INCREMENT` in MySQL and MariaDB) causes the entire table to be rewritten. During this time, reads and writes are blocked in Postgres, and writes are blocked in MySQL and MariaDB.
265
266
 
266
267
  ```ruby
267
- class AddIdToCitiesUsers < ActiveRecord::Migration[7.1]
268
+ class AddIdToCitiesUsers < ActiveRecord::Migration[8.0]
268
269
  def change
269
270
  add_column :cities_users, :id, :primary_key
270
271
  end
@@ -284,7 +285,7 @@ Create a new table and migrate the data with the same steps as [renaming a table
284
285
  Adding a stored generated column causes the entire table to be rewritten. During this time, reads and writes are blocked in Postgres, and writes are blocked in MySQL and MariaDB.
285
286
 
286
287
  ```ruby
287
- class AddSomeColumnToUsers < ActiveRecord::Migration[7.1]
288
+ class AddSomeColumnToUsers < ActiveRecord::Migration[8.0]
288
289
  def change
289
290
  add_column :users, :some_column, :virtual, type: :string, as: "...", stored: true
290
291
  end
@@ -304,7 +305,7 @@ Add a non-generated column and use callbacks or triggers instead (or a virtual g
304
305
  Adding a check constraint blocks reads and writes in Postgres and blocks writes in MySQL and MariaDB while every row is checked.
305
306
 
306
307
  ```ruby
307
- class AddCheckConstraint < ActiveRecord::Migration[7.1]
308
+ class AddCheckConstraint < ActiveRecord::Migration[8.0]
308
309
  def change
309
310
  add_check_constraint :users, "price > 0", name: "price_check"
310
311
  end
@@ -316,7 +317,7 @@ end
316
317
  Add the check constraint without validating existing rows:
317
318
 
318
319
  ```ruby
319
- class AddCheckConstraint < ActiveRecord::Migration[7.1]
320
+ class AddCheckConstraint < ActiveRecord::Migration[8.0]
320
321
  def change
321
322
  add_check_constraint :users, "price > 0", name: "price_check", validate: false
322
323
  end
@@ -326,7 +327,7 @@ end
326
327
  Then validate them in a separate migration.
327
328
 
328
329
  ```ruby
329
- class ValidateCheckConstraint < ActiveRecord::Migration[7.1]
330
+ class ValidateCheckConstraint < ActiveRecord::Migration[8.0]
330
331
  def change
331
332
  validate_check_constraint :users, name: "price_check"
332
333
  end
@@ -342,7 +343,7 @@ end
342
343
  Strong Migrations can’t ensure safety for raw SQL statements. Make really sure that what you’re doing is safe, then use:
343
344
 
344
345
  ```ruby
345
- class ExecuteSQL < ActiveRecord::Migration[7.1]
346
+ class ExecuteSQL < ActiveRecord::Migration[8.0]
346
347
  def change
347
348
  safety_assured { execute "..." }
348
349
  end
@@ -351,12 +352,14 @@ end
351
352
 
352
353
  ### Backfilling data
353
354
 
355
+ Note: Strong Migrations does not detect dangerous backfills.
356
+
354
357
  #### Bad
355
358
 
356
359
  Active Record creates a transaction around each migration, and backfilling in the same transaction that alters a table keeps the table locked for the [duration of the backfill](https://wework.github.io/data/2015/11/05/add-columns-with-default-values-to-large-tables-in-rails-postgres/).
357
360
 
358
361
  ```ruby
359
- class AddSomeColumnToUsers < ActiveRecord::Migration[7.1]
362
+ class AddSomeColumnToUsers < ActiveRecord::Migration[8.0]
360
363
  def change
361
364
  add_column :users, :some_column, :text
362
365
  User.update_all some_column: "default_value"
@@ -371,18 +374,20 @@ Also, running a single query to update data can cause issues for large tables.
371
374
  There are three keys to backfilling safely: batching, throttling, and running it outside a transaction. Use the Rails console or a separate migration with `disable_ddl_transaction!`.
372
375
 
373
376
  ```ruby
374
- class BackfillSomeColumn < ActiveRecord::Migration[7.1]
377
+ class BackfillSomeColumn < ActiveRecord::Migration[8.0]
375
378
  disable_ddl_transaction!
376
379
 
377
380
  def up
378
- User.unscoped.in_batches do |relation|
379
- relation.update_all some_column: "default_value"
381
+ User.unscoped.in_batches(of: 10000) do |relation|
382
+ relation.where(some_column: nil).update_all some_column: "default_value"
380
383
  sleep(0.01) # throttle
381
384
  end
382
385
  end
383
386
  end
384
387
  ```
385
388
 
389
+ Note: If backfilling with a method other than `update_all`, use `User.reset_column_information` to ensure the model has up-to-date column information.
390
+
386
391
  ### Adding an index non-concurrently
387
392
 
388
393
  :turtle: Safe by default available
@@ -392,7 +397,7 @@ end
392
397
  In Postgres, adding an index non-concurrently blocks writes.
393
398
 
394
399
  ```ruby
395
- class AddSomeIndexToUsers < ActiveRecord::Migration[7.1]
400
+ class AddSomeIndexToUsers < ActiveRecord::Migration[8.0]
396
401
  def change
397
402
  add_index :users, :some_column
398
403
  end
@@ -404,7 +409,7 @@ end
404
409
  Add indexes concurrently.
405
410
 
406
411
  ```ruby
407
- class AddSomeIndexToUsers < ActiveRecord::Migration[7.1]
412
+ class AddSomeIndexToUsers < ActiveRecord::Migration[8.0]
408
413
  disable_ddl_transaction!
409
414
 
410
415
  def change
@@ -430,7 +435,7 @@ rails g index table column
430
435
  Rails adds an index non-concurrently to references by default, which blocks writes in Postgres.
431
436
 
432
437
  ```ruby
433
- class AddReferenceToUsers < ActiveRecord::Migration[7.1]
438
+ class AddReferenceToUsers < ActiveRecord::Migration[8.0]
434
439
  def change
435
440
  add_reference :users, :city
436
441
  end
@@ -442,7 +447,7 @@ end
442
447
  Make sure the index is added concurrently.
443
448
 
444
449
  ```ruby
445
- class AddReferenceToUsers < ActiveRecord::Migration[7.1]
450
+ class AddReferenceToUsers < ActiveRecord::Migration[8.0]
446
451
  disable_ddl_transaction!
447
452
 
448
453
  def change
@@ -460,7 +465,7 @@ end
460
465
  In Postgres, adding a foreign key blocks writes on both tables.
461
466
 
462
467
  ```ruby
463
- class AddForeignKeyOnUsers < ActiveRecord::Migration[7.1]
468
+ class AddForeignKeyOnUsers < ActiveRecord::Migration[8.0]
464
469
  def change
465
470
  add_foreign_key :users, :orders
466
471
  end
@@ -470,7 +475,7 @@ end
470
475
  or
471
476
 
472
477
  ```ruby
473
- class AddReferenceToUsers < ActiveRecord::Migration[7.1]
478
+ class AddReferenceToUsers < ActiveRecord::Migration[8.0]
474
479
  def change
475
480
  add_reference :users, :order, foreign_key: true
476
481
  end
@@ -482,7 +487,7 @@ end
482
487
  Add the foreign key without validating existing rows:
483
488
 
484
489
  ```ruby
485
- class AddForeignKeyOnUsers < ActiveRecord::Migration[7.1]
490
+ class AddForeignKeyOnUsers < ActiveRecord::Migration[8.0]
486
491
  def change
487
492
  add_foreign_key :users, :orders, validate: false
488
493
  end
@@ -492,7 +497,7 @@ end
492
497
  Then validate them in a separate migration.
493
498
 
494
499
  ```ruby
495
- class ValidateForeignKeyOnUsers < ActiveRecord::Migration[7.1]
500
+ class ValidateForeignKeyOnUsers < ActiveRecord::Migration[8.0]
496
501
  def change
497
502
  validate_foreign_key :users, :orders
498
503
  end
@@ -506,7 +511,7 @@ end
506
511
  In Postgres, adding a unique constraint creates a unique index, which blocks reads and writes.
507
512
 
508
513
  ```ruby
509
- class AddUniqueConstraint < ActiveRecord::Migration[7.1]
514
+ class AddUniqueConstraint < ActiveRecord::Migration[8.0]
510
515
  def change
511
516
  add_unique_constraint :users, :some_column
512
517
  end
@@ -518,7 +523,7 @@ end
518
523
  Create a unique index concurrently, then use it for the constraint.
519
524
 
520
525
  ```ruby
521
- class AddUniqueConstraint < ActiveRecord::Migration[7.1]
526
+ class AddUniqueConstraint < ActiveRecord::Migration[8.0]
522
527
  disable_ddl_transaction!
523
528
 
524
529
  def up
@@ -539,7 +544,7 @@ end
539
544
  In Postgres, adding an exclusion constraint blocks reads and writes while every row is checked.
540
545
 
541
546
  ```ruby
542
- class AddExclusionConstraint < ActiveRecord::Migration[7.1]
547
+ class AddExclusionConstraint < ActiveRecord::Migration[8.0]
543
548
  def change
544
549
  add_exclusion_constraint :users, "number WITH =", using: :gist
545
550
  end
@@ -557,7 +562,7 @@ end
557
562
  In Postgres, there’s no equality operator for the `json` column type, which can cause errors for existing `SELECT DISTINCT` queries in your application.
558
563
 
559
564
  ```ruby
560
- class AddPropertiesToUsers < ActiveRecord::Migration[7.1]
565
+ class AddPropertiesToUsers < ActiveRecord::Migration[8.0]
561
566
  def change
562
567
  add_column :users, :properties, :json
563
568
  end
@@ -569,7 +574,7 @@ end
569
574
  Use `jsonb` instead.
570
575
 
571
576
  ```ruby
572
- class AddPropertiesToUsers < ActiveRecord::Migration[7.1]
577
+ class AddPropertiesToUsers < ActiveRecord::Migration[8.0]
573
578
  def change
574
579
  add_column :users, :properties, :jsonb
575
580
  end
@@ -585,7 +590,7 @@ end
585
590
  In Postgres, setting `NOT NULL` on an existing column blocks reads and writes while every row is checked.
586
591
 
587
592
  ```ruby
588
- class SetSomeColumnNotNull < ActiveRecord::Migration[7.1]
593
+ class SetSomeColumnNotNull < ActiveRecord::Migration[8.0]
589
594
  def change
590
595
  change_column_null :users, :some_column, false
591
596
  end
@@ -597,7 +602,7 @@ end
597
602
  Instead, add a check constraint.
598
603
 
599
604
  ```ruby
600
- class SetSomeColumnNotNull < ActiveRecord::Migration[7.1]
605
+ class SetSomeColumnNotNull < ActiveRecord::Migration[8.0]
601
606
  def change
602
607
  add_check_constraint :users, "some_column IS NOT NULL", name: "users_some_column_null", validate: false
603
608
  end
@@ -607,12 +612,17 @@ end
607
612
  Then validate it in a separate migration. Once the check constraint is validated, you can safely set `NOT NULL` on the column and drop the check constraint.
608
613
 
609
614
  ```ruby
610
- class ValidateSomeColumnNotNull < ActiveRecord::Migration[7.1]
611
- def change
615
+ class ValidateSomeColumnNotNull < ActiveRecord::Migration[8.0]
616
+ def up
612
617
  validate_check_constraint :users, name: "users_some_column_null"
613
618
  change_column_null :users, :some_column, false
614
619
  remove_check_constraint :users, name: "users_some_column_null"
615
620
  end
621
+
622
+ def down
623
+ add_check_constraint :users, "some_column IS NOT NULL", name: "users_some_column_null", validate: false
624
+ change_column_null :users, :some_column, true
625
+ end
616
626
  end
617
627
  ```
618
628
 
@@ -623,7 +633,7 @@ end
623
633
  Adding a column with a volatile default value to an existing table causes the entire table to be rewritten. During this time, reads and writes are blocked.
624
634
 
625
635
  ```ruby
626
- class AddSomeColumnToUsers < ActiveRecord::Migration[7.1]
636
+ class AddSomeColumnToUsers < ActiveRecord::Migration[8.0]
627
637
  def change
628
638
  add_column :users, :some_column, :uuid, default: "gen_random_uuid()"
629
639
  end
@@ -635,7 +645,7 @@ end
635
645
  Instead, add the column without a default value, then change the default.
636
646
 
637
647
  ```ruby
638
- class AddSomeColumnToUsers < ActiveRecord::Migration[7.1]
648
+ class AddSomeColumnToUsers < ActiveRecord::Migration[8.0]
639
649
  def up
640
650
  add_column :users, :some_column, :uuid
641
651
  change_column_default :users, :some_column, from: nil, to: "gen_random_uuid()"
@@ -649,6 +659,31 @@ end
649
659
 
650
660
  Then [backfill the data](#backfilling-data).
651
661
 
662
+ ### Renaming a schema
663
+
664
+ #### Bad
665
+
666
+ Renaming a schema that’s in use will cause errors in your application.
667
+
668
+ ```ruby
669
+ class RenameUsersToCustomers < ActiveRecord::Migration[8.1]
670
+ def change
671
+ rename_schema :users, :customers
672
+ end
673
+ end
674
+ ```
675
+
676
+ #### Good
677
+
678
+ A safer approach is to:
679
+
680
+ 1. Create a new schema
681
+ 2. Write to both schemas
682
+ 3. Backfill data from the old schema to the new schema
683
+ 4. Move reads from the old schema to the new schema
684
+ 5. Stop writing to the old schema
685
+ 6. Drop the old schema
686
+
652
687
  ### Changing the default value of a column
653
688
 
654
689
  #### Bad
@@ -686,7 +721,7 @@ config.active_record.partial_inserts = false
686
721
  Adding a non-unique index with more than three columns rarely improves performance.
687
722
 
688
723
  ```ruby
689
- class AddSomeIndexToUsers < ActiveRecord::Migration[7.1]
724
+ class AddSomeIndexToUsers < ActiveRecord::Migration[8.0]
690
725
  def change
691
726
  add_index :users, [:a, :b, :c, :d]
692
727
  end
@@ -698,7 +733,7 @@ end
698
733
  Instead, start an index with columns that narrow down the results the most.
699
734
 
700
735
  ```ruby
701
- class AddSomeIndexToUsers < ActiveRecord::Migration[7.1]
736
+ class AddSomeIndexToUsers < ActiveRecord::Migration[8.0]
702
737
  def change
703
738
  add_index :users, [:d, :b]
704
739
  end
@@ -712,7 +747,7 @@ For Postgres, be sure to add them concurrently.
712
747
  To mark a step in the migration as safe, despite using a method that might otherwise be dangerous, wrap it in a `safety_assured` block.
713
748
 
714
749
  ```ruby
715
- class MySafeMigration < ActiveRecord::Migration[7.1]
750
+ class MySafeMigration < ActiveRecord::Migration[8.0]
716
751
  def change
717
752
  safety_assured { remove_column :users, :some_column }
718
753
  end
@@ -723,7 +758,7 @@ Certain methods like `execute` and `change_table` cannot be inspected and are pr
723
758
 
724
759
  ## Safe by Default
725
760
 
726
- Make operations safe by default.
761
+ Make certain operations safe by default. This allows you to write the code under the "Bad" section, but the migration will be performed as if you had written the "Good" version.
727
762
 
728
763
  - adding and removing an index
729
764
  - adding a foreign key
@@ -772,6 +807,16 @@ StrongMigrations.disable_check(:add_index)
772
807
 
773
808
  Check the [source code](https://github.com/ankane/strong_migrations/blob/master/lib/strong_migrations/error_messages.rb) for the list of keys.
774
809
 
810
+ ## Skip Databases
811
+
812
+ Skip checks and other functionality for specific databases with:
813
+
814
+ ```ruby
815
+ StrongMigrations.skip_database(:catalog)
816
+ ```
817
+
818
+ Note: This does not affect `alphabetize_schema`.
819
+
775
820
  ## Down Migrations / Rollbacks
776
821
 
777
822
  By default, checks are disabled when migrating down. Enable them with:
@@ -853,7 +898,19 @@ production:
853
898
 
854
899
  For HTTP connections, Redis, and other services, check out [this guide](https://github.com/ankane/the-ultimate-guide-to-ruby-timeouts).
855
900
 
856
- ## Lock Timeout Retries [experimental]
901
+ ## Invalid Indexes
902
+
903
+ In Postgres, adding an index non-concurrently can leave behind an invalid index if the lock timeout is reached. Running the migration again can result in an error.
904
+
905
+ To automatically remove the invalid index when the migration runs again, use:
906
+
907
+ ```ruby
908
+ StrongMigrations.remove_invalid_indexes = true
909
+ ```
910
+
911
+ ## Lock Timeout Retries
912
+
913
+ Note: This feature is experimental.
857
914
 
858
915
  There’s the option to automatically retry statements for migrations when the lock timeout is reached. Here’s how it works:
859
916
 
@@ -877,7 +934,7 @@ StrongMigrations.lock_timeout_retry_delay = 10.seconds
877
934
  To mark migrations as safe that were created before installing this gem, create an initializer with:
878
935
 
879
936
  ```ruby
880
- StrongMigrations.start_after = 20230101000000
937
+ StrongMigrations.start_after = 20250101000000
881
938
  ```
882
939
 
883
940
  Use the version from your latest migration.
@@ -934,15 +991,18 @@ You probably don’t need this gem for smaller projects, as operations that are
934
991
 
935
992
  ## Additional Reading
936
993
 
937
- - [Rails Migrations with No Downtime](https://pedro.herokuapp.com/past/2011/7/13/rails_migrations_with_no_downtime/)
938
994
  - [PostgreSQL at Scale: Database Schema Changes Without Downtime](https://medium.com/braintree-product-technology/postgresql-at-scale-database-schema-changes-without-downtime-20d3749ed680)
939
- - [An Overview of DDL Algorithms in MySQL](https://mydbops.wordpress.com/2020/03/04/an-overview-of-ddl-algorithms-in-mysql-covers-mysql-8/)
995
+ - [MySQL InnoDB Online DDL Operations](https://dev.mysql.com/doc/refman/en/innodb-online-ddl-operations.html)
940
996
  - [MariaDB InnoDB Online DDL Overview](https://mariadb.com/kb/en/innodb-online-ddl-overview/)
941
997
 
942
998
  ## Credits
943
999
 
944
1000
  Thanks to Bob Remeika and David Waller for the [original code](https://github.com/foobarfighter/safe-migrations) and [Sean Huber](https://github.com/LendingHome/zero_downtime_migrations) for the bad/good readme format.
945
1001
 
1002
+ ## History
1003
+
1004
+ View the [changelog](https://github.com/ankane/strong_migrations/blob/master/CHANGELOG.md)
1005
+
946
1006
  ## Contributing
947
1007
 
948
1008
  Everyone is encouraged to help improve this project. Here are a few ways you can help:
@@ -20,6 +20,9 @@ StrongMigrations.auto_analyze = true
20
20
  # end
21
21
  # end<% if postgresql? %>
22
22
 
23
+ # Remove invalid indexes when rerunning migrations
24
+ # StrongMigrations.remove_invalid_indexes = true
25
+
23
26
  # Make some operations safe by default
24
27
  # See https://github.com/ankane/strong_migrations#safe-by-default
25
28
  # StrongMigrations.safe_by_default = true<% end %>
@@ -13,11 +13,15 @@ module StrongMigrations
13
13
  end
14
14
 
15
15
  def set_statement_timeout(timeout)
16
- raise StrongMigrations::Error, "Statement timeout not supported for this database"
16
+ # do nothing
17
+ end
18
+
19
+ def set_transaction_timeout(timeout)
20
+ # do nothing
17
21
  end
18
22
 
19
23
  def set_lock_timeout(timeout)
20
- raise StrongMigrations::Error, "Lock timeout not supported for this database"
24
+ # do nothing
21
25
  end
22
26
 
23
27
  def check_lock_timeout(limit)
@@ -40,6 +44,9 @@ module StrongMigrations
40
44
  ["primary_key"]
41
45
  end
42
46
 
47
+ def max_constraint_name_length
48
+ end
49
+
43
50
  private
44
51
 
45
52
  def connection
@@ -92,6 +92,10 @@ module StrongMigrations
92
92
  "writes"
93
93
  end
94
94
 
95
+ def max_constraint_name_length
96
+ 64
97
+ end
98
+
95
99
  private
96
100
 
97
101
  # do not memoize
@@ -23,6 +23,11 @@ module StrongMigrations
23
23
  set_timeout("statement_timeout", timeout)
24
24
  end
25
25
 
26
+ def set_transaction_timeout(timeout)
27
+ # TODO make sure true version supports it as well?
28
+ set_timeout("transaction_timeout", timeout) if server_version >= Gem::Version.new("17")
29
+ end
30
+
26
31
  def set_lock_timeout(timeout)
27
32
  set_timeout("lock_timeout", timeout)
28
33
  end
@@ -127,21 +132,6 @@ module StrongMigrations
127
132
  safe
128
133
  end
129
134
 
130
- def constraints(table_name)
131
- query = <<~SQL
132
- SELECT
133
- conname AS name,
134
- pg_get_constraintdef(oid) AS def
135
- FROM
136
- pg_constraint
137
- WHERE
138
- contype = 'c' AND
139
- convalidated AND
140
- conrelid = #{connection.quote(connection.quote_table_name(table_name))}::regclass
141
- SQL
142
- select_all(query.squish).to_a
143
- end
144
-
145
135
  def writes_blocked?
146
136
  query = <<~SQL
147
137
  SELECT
@@ -173,6 +163,15 @@ module StrongMigrations
173
163
  ["primary_key", "serial", "bigserial"]
174
164
  end
175
165
 
166
+ def max_constraint_name_length
167
+ 63
168
+ end
169
+
170
+ def constraints(table, column)
171
+ # TODO improve column check
172
+ connection.check_constraints(table).select { |c| /\b#{Regexp.escape(column.to_s)}\b/.match?(c.expression) }
173
+ end
174
+
176
175
  private
177
176
 
178
177
  def set_timeout(setting, timeout)
@@ -210,15 +209,9 @@ module StrongMigrations
210
209
  end
211
210
 
212
211
  def datetime_type
213
- key =
214
- if ActiveRecord::VERSION::MAJOR >= 7
215
- # https://github.com/rails/rails/pull/41084
216
- # no need to support custom datetime_types
217
- connection.class.datetime_type
218
- else
219
- # https://github.com/rails/rails/issues/21126#issuecomment-327895275
220
- :datetime
221
- end
212
+ # https://github.com/rails/rails/pull/41084
213
+ # no need to support custom datetime_types
214
+ key = connection.class.datetime_type
222
215
 
223
216
  # could be timestamp, timestamp without time zone, timestamp with time zone, etc
224
217
  connection.class.const_get(:NATIVE_DATABASE_TYPES).fetch(key).fetch(:name)