strong_migrations 2.3.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +26 -2
- data/lib/generators/strong_migrations/templates/initializer.rb.tt +3 -0
- data/lib/strong_migrations/adapters/abstract_adapter.rb +4 -0
- data/lib/strong_migrations/adapters/postgresql_adapter.rb +5 -15
- data/lib/strong_migrations/checker.rb +18 -4
- data/lib/strong_migrations/checks.rb +4 -0
- data/lib/strong_migrations/error_messages.rb +11 -0
- data/lib/strong_migrations/migration.rb +1 -4
- data/lib/strong_migrations/migrator.rb +1 -1
- data/lib/strong_migrations/safe_methods.rb +0 -2
- data/lib/strong_migrations/version.rb +1 -1
- data/lib/strong_migrations.rb +1 -1
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 971d5d1eabb91dc04c72cc99a24f8b92f1b0d31d8d28369577f48c283b8d8624
|
4
|
+
data.tar.gz: '08a413578f564ada7f9768aeaf469719ca051e4c37057be6324e593c73fb3144'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8ca27268e166609ec8253ce686c6fe9cbe6d7c4b298f8c80ce7f1690e76a2c997fad2806cce52c9765f6ee92e7e389fdf6c830d3ca8ebb0241574adc02c4b57
|
7
|
+
data.tar.gz: 18731d2b1bdd12698d6b860a470249a24ea12aaa0b5b74b6510d41527ef2126c46b27ef4aa7c7adb1437bd7a006d0bb7c46490d24ec15720009723e5b0d8eca4
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
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
|
+
|
1
12
|
## 2.3.0 (2025-04-03)
|
2
13
|
|
3
14
|
- Added check for `change_column` for columns with check constraints with Postgres
|
data/README.md
CHANGED
@@ -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
|
|
@@ -658,6 +659,31 @@ end
|
|
658
659
|
|
659
660
|
Then [backfill the data](#backfilling-data).
|
660
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
|
+
|
661
687
|
### Changing the default value of a column
|
662
688
|
|
663
689
|
#### Bad
|
@@ -882,8 +908,6 @@ To automatically remove the invalid index when the migration runs again, use:
|
|
882
908
|
StrongMigrations.remove_invalid_indexes = true
|
883
909
|
```
|
884
910
|
|
885
|
-
Note: This feature is experimental.
|
886
|
-
|
887
911
|
## Lock Timeout Retries
|
888
912
|
|
889
913
|
Note: This feature is experimental.
|
@@ -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 %>
|
@@ -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
|
-
# TODO remove when Active Record < 7.1 is no longer supported
|
131
|
-
def index_invalid?(table_name, index_name)
|
132
|
-
query = <<~SQL
|
133
|
-
SELECT
|
134
|
-
indisvalid
|
135
|
-
FROM
|
136
|
-
pg_index
|
137
|
-
WHERE
|
138
|
-
indrelid = to_regclass(#{connection.quote(connection.quote_table_name(table_name))}) AND
|
139
|
-
indexrelid = to_regclass(#{connection.quote(connection.quote_table_name(index_name))}) AND
|
140
|
-
indisvalid = false
|
141
|
-
SQL
|
142
|
-
select_all(query.squish).any?
|
143
|
-
end
|
144
|
-
|
145
135
|
def writes_blocked?
|
146
136
|
query = <<~SQL
|
147
137
|
SELECT
|
@@ -79,6 +79,8 @@ module StrongMigrations
|
|
79
79
|
check_remove_index(*args)
|
80
80
|
when :rename_column
|
81
81
|
check_rename_column
|
82
|
+
when :rename_schema
|
83
|
+
check_rename_schema
|
82
84
|
when :rename_table
|
83
85
|
check_rename_table
|
84
86
|
when :validate_check_constraint
|
@@ -111,7 +113,7 @@ module StrongMigrations
|
|
111
113
|
end
|
112
114
|
|
113
115
|
# outdated statistics + a new index can hurt performance of existing queries
|
114
|
-
if StrongMigrations.auto_analyze && direction == :up && method
|
116
|
+
if StrongMigrations.auto_analyze && direction == :up && adds_index?(method, *args)
|
115
117
|
adapter.analyze_table(args[0])
|
116
118
|
end
|
117
119
|
|
@@ -181,6 +183,9 @@ module StrongMigrations
|
|
181
183
|
if StrongMigrations.statement_timeout
|
182
184
|
adapter.set_statement_timeout(StrongMigrations.statement_timeout)
|
183
185
|
end
|
186
|
+
if StrongMigrations.transaction_timeout
|
187
|
+
adapter.set_transaction_timeout(StrongMigrations.transaction_timeout)
|
188
|
+
end
|
184
189
|
if StrongMigrations.lock_timeout
|
185
190
|
adapter.set_lock_timeout(StrongMigrations.lock_timeout)
|
186
191
|
end
|
@@ -253,6 +258,18 @@ module StrongMigrations
|
|
253
258
|
end
|
254
259
|
end
|
255
260
|
|
261
|
+
def adds_index?(method, *args)
|
262
|
+
case method
|
263
|
+
when :add_index
|
264
|
+
true
|
265
|
+
when :add_reference, :add_belongs_to
|
266
|
+
options = args.extract_options!
|
267
|
+
!!options.fetch(:index, true)
|
268
|
+
else
|
269
|
+
false
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
256
273
|
# REINDEX INDEX CONCURRENTLY leaves a new invalid index if it fails, so use remove_index instead
|
257
274
|
def remove_invalid_index_if_needed(*args)
|
258
275
|
options = args.extract_options!
|
@@ -264,9 +281,6 @@ module StrongMigrations
|
|
264
281
|
table, columns = args
|
265
282
|
index_name = options.fetch(:name, connection.index_name(table, columns))
|
266
283
|
|
267
|
-
# valid option is ignored for Active Record < 7.1, so check name as well
|
268
|
-
return if ar_version < 7.1 && !adapter.index_invalid?(table, index_name)
|
269
|
-
|
270
284
|
@migration.say("Attempting to remove invalid index")
|
271
285
|
without_retries do
|
272
286
|
# TODO pass index schema for extra safety?
|
@@ -102,6 +102,17 @@ in your application. A safer approach is to:
|
|
102
102
|
5. Stop writing to the old column
|
103
103
|
6. Drop the old column",
|
104
104
|
|
105
|
+
rename_schema:
|
106
|
+
"Renaming a schema that's in use will cause errors
|
107
|
+
in your application. A safer approach is to:
|
108
|
+
|
109
|
+
1. Create a new schema
|
110
|
+
2. Write to both schemas
|
111
|
+
3. Backfill data from the old schema to the new schema
|
112
|
+
4. Move reads from the old schema to the new schema
|
113
|
+
5. Stop writing to the old schema
|
114
|
+
6. Drop the old schema",
|
115
|
+
|
105
116
|
rename_table:
|
106
117
|
"Renaming a table that's in use will cause errors
|
107
118
|
in your application. A safer approach is to:
|
@@ -7,10 +7,7 @@ module StrongMigrations
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def method_missing(method, *args)
|
10
|
-
return super if is_a?(ActiveRecord::Schema)
|
11
|
-
|
12
|
-
# Active Record 7.0.2+ versioned schema
|
13
|
-
return super if defined?(ActiveRecord::Schema::Definition) && is_a?(ActiveRecord::Schema::Definition)
|
10
|
+
return super if is_a?(ActiveRecord::Schema) || is_a?(ActiveRecord::Schema::Definition)
|
14
11
|
|
15
12
|
catch(:safe) do
|
16
13
|
strong_migrations_checker.perform(method, *args) do
|
@@ -4,7 +4,7 @@ module StrongMigrations
|
|
4
4
|
return super unless StrongMigrations.lock_timeout_retries > 0 && use_transaction?(migration)
|
5
5
|
|
6
6
|
# handle MigrationProxy class
|
7
|
-
migration = migration.send(:migration) if migration.respond_to?(:migration, true)
|
7
|
+
migration = migration.send(:migration) if !migration.is_a?(ActiveRecord::Migration) && migration.respond_to?(:migration, true)
|
8
8
|
|
9
9
|
checker = migration.send(:strong_migrations_checker)
|
10
10
|
return super if checker.skip?
|
@@ -46,8 +46,6 @@ module StrongMigrations
|
|
46
46
|
def safe_add_foreign_key(from_table, to_table, *args, **options)
|
47
47
|
@migration.reversible do |dir|
|
48
48
|
dir.up do
|
49
|
-
# validate option is unintentionally ignored for Active Record < 7.1
|
50
|
-
# https://github.com/rails/rails/pull/45896
|
51
49
|
if !connection.foreign_key_exists?(from_table, to_table, **options.merge(validate: false))
|
52
50
|
@migration.add_foreign_key(from_table, to_table, *args, **options.merge(validate: false))
|
53
51
|
end
|
data/lib/strong_migrations.rb
CHANGED
@@ -29,7 +29,7 @@ module StrongMigrations
|
|
29
29
|
:target_postgresql_version, :target_mysql_version, :target_mariadb_version,
|
30
30
|
:enabled_checks, :lock_timeout, :statement_timeout, :check_down, :target_version,
|
31
31
|
:safe_by_default, :target_sql_mode, :lock_timeout_retries, :lock_timeout_retry_delay,
|
32
|
-
:alphabetize_schema, :skipped_databases, :remove_invalid_indexes
|
32
|
+
:alphabetize_schema, :skipped_databases, :remove_invalid_indexes, :transaction_timeout
|
33
33
|
attr_writer :lock_timeout_limit
|
34
34
|
end
|
35
35
|
self.auto_analyze = false
|
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: 2.
|
4
|
+
version: 2.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
- David Waller
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '7'
|
20
|
+
version: '7.1'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '7'
|
27
|
+
version: '7.1'
|
28
28
|
email:
|
29
29
|
- andrew@ankane.org
|
30
30
|
- bob.remeika@gmail.com
|
@@ -65,14 +65,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '3.
|
68
|
+
version: '3.2'
|
69
69
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
70
|
requirements:
|
71
71
|
- - ">="
|
72
72
|
- !ruby/object:Gem::Version
|
73
73
|
version: '0'
|
74
74
|
requirements: []
|
75
|
-
rubygems_version: 3.6.
|
75
|
+
rubygems_version: 3.6.9
|
76
76
|
specification_version: 4
|
77
77
|
summary: Catch unsafe migrations in development
|
78
78
|
test_files: []
|