online_migrations 0.5.1 → 0.5.3
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 +36 -0
- data/lib/generators/online_migrations/install_generator.rb +5 -5
- data/lib/generators/online_migrations/templates/initializer.rb.tt +4 -4
- data/lib/online_migrations/command_checker.rb +22 -9
- data/lib/online_migrations/config.rb +3 -7
- data/lib/online_migrations/error_messages.rb +10 -0
- data/lib/online_migrations/index_definition.rb +1 -4
- data/lib/online_migrations/schema_cache.rb +4 -2
- data/lib/online_migrations/schema_statements.rb +43 -5
- data/lib/online_migrations/utils.rb +4 -2
- data/lib/online_migrations/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0ac8a2eb2657fcc3536a9b56d16298f90f8e1a5e626ba52a6e9703b5bcaa7df0
|
|
4
|
+
data.tar.gz: c5357f94854fb43d1b8404ed9dcfafc2178430aeb9c6d69555f50629a94da3bd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4ccbc274c76ab01f8ece559b3fee27c1c5c0c495225b393c3a4afb7941f0b61d3aab9ef2885195be78ed00f29bd5e6b18e3fe0cb044b745cd791aacf34283492
|
|
7
|
+
data.tar.gz: 04fb250e30e7620ac1bd06fddf24a5fdfe616f285422e47e19423e23be0c8117e57d45e45029a2e1212cc5e6ad9baf3605fac8b038152fdc73b2d9a818ba211c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
## master (unreleased)
|
|
2
2
|
|
|
3
|
+
## 0.5.3 (2022-11-10)
|
|
4
|
+
|
|
5
|
+
- Fix removing index by name
|
|
6
|
+
- Fix multiple databases support for `start_after` and `target_version` configs
|
|
7
|
+
- Fix error when `Rails` defined without `Rails.env`
|
|
8
|
+
- Improve error message for adding column with a NULL default for PostgreSQL < 11
|
|
9
|
+
|
|
10
|
+
## 0.5.2 (2022-10-04)
|
|
11
|
+
|
|
12
|
+
- Fix sequence resetting in tests that use fixtures
|
|
13
|
+
|
|
14
|
+
- Fix `update_column_in_batches` for SQL subquery values
|
|
15
|
+
|
|
16
|
+
It generated inefficient queries before, e.g.:
|
|
17
|
+
|
|
18
|
+
```ruby
|
|
19
|
+
update_column_in_batches(:users, :comments_count, Arel.sql(<<~SQL))
|
|
20
|
+
(select count(*) from comments where comments.user_id = users.id)
|
|
21
|
+
SQL
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Generated SQL queries before:
|
|
25
|
+
```sql
|
|
26
|
+
update users
|
|
27
|
+
set comments_count = (..count subquery..)
|
|
28
|
+
where comments_count is null or comments_count != (..count subquery..)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Generated SQL queries now:
|
|
32
|
+
```sql
|
|
33
|
+
update users set comments_count = (..count subquery..)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
- Fix check for `add_column` with `default: nil` for PostgreSQL < 11
|
|
37
|
+
- Replacing a unique index when other unique index with the prefix of columns exists is safe
|
|
38
|
+
|
|
3
39
|
## 0.5.1 (2022-07-19)
|
|
4
40
|
|
|
5
41
|
- Raise for possible index corruption in all environments (previously, the check was made only
|
|
@@ -10,21 +10,21 @@ module OnlineMigrations
|
|
|
10
10
|
|
|
11
11
|
source_root File.expand_path("templates", __dir__)
|
|
12
12
|
|
|
13
|
-
def create_migration_file
|
|
14
|
-
migration_template("migration.rb", File.join(migrations_dir, "install_online_migrations.rb"))
|
|
15
|
-
end
|
|
16
|
-
|
|
17
13
|
def copy_initializer_file
|
|
18
14
|
template("initializer.rb", "config/initializers/online_migrations.rb")
|
|
19
15
|
end
|
|
20
16
|
|
|
17
|
+
def create_migration_file
|
|
18
|
+
migration_template("migration.rb", File.join(migrations_dir, "install_online_migrations.rb"))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
21
|
private
|
|
22
22
|
def migration_parent
|
|
23
23
|
Utils.migration_parent_string
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def start_after
|
|
27
|
-
self.class.
|
|
27
|
+
self.class.current_migration_number(migrations_dir)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def migrations_dir
|
|
@@ -59,11 +59,11 @@ OnlineMigrations.configure do |config|
|
|
|
59
59
|
|
|
60
60
|
# Add custom checks. Use the `stop!` method to stop migrations.
|
|
61
61
|
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
64
|
-
#
|
|
65
|
-
# end
|
|
62
|
+
# config.add_check do |method, args|
|
|
63
|
+
# if method == :add_column && args[0].to_s == "users"
|
|
64
|
+
# stop!("No more columns on the users table")
|
|
66
65
|
# end
|
|
66
|
+
# end
|
|
67
67
|
|
|
68
68
|
# ==> Background migrations configuration
|
|
69
69
|
# The number of rows to process in a single background migration run.
|
|
@@ -174,13 +174,18 @@ module OnlineMigrations
|
|
|
174
174
|
def add_column(table_name, column_name, type, **options)
|
|
175
175
|
default = options[:default]
|
|
176
176
|
volatile_default = false
|
|
177
|
-
if !new_or_small_table?(table_name) &&
|
|
178
|
-
(postgresql_version < Gem::Version.new("11") || (volatile_default = Utils.volatile_default?(connection, type, default)))
|
|
177
|
+
if !new_or_small_table?(table_name) && options.key?(:default) &&
|
|
178
|
+
(postgresql_version < Gem::Version.new("11") || (!default.nil? && (volatile_default = Utils.volatile_default?(connection, type, default))))
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
if default.nil?
|
|
181
|
+
raise_error :add_column_with_default_null,
|
|
182
|
+
code: command_str(:add_column, table_name, column_name, type, options.except(:default))
|
|
183
|
+
else
|
|
184
|
+
raise_error :add_column_with_default,
|
|
185
|
+
code: command_str(:add_column_with_default, table_name, column_name, type, options),
|
|
186
|
+
not_null: options[:null] == false,
|
|
187
|
+
volatile_default: volatile_default
|
|
188
|
+
end
|
|
184
189
|
end
|
|
185
190
|
|
|
186
191
|
if type == :json
|
|
@@ -478,9 +483,17 @@ module OnlineMigrations
|
|
|
478
483
|
command: command_str(:remove_index, table_name, **options.merge(algorithm: :concurrently))
|
|
479
484
|
end
|
|
480
485
|
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
486
|
+
index_def = connection.indexes(table_name).find do |index|
|
|
487
|
+
index.name == options[:name].to_s ||
|
|
488
|
+
Array(index.columns).map(&:to_s) == Array(options[:column]).map(&:to_s)
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
if index_def
|
|
492
|
+
existing_options = [:name, :columns, :unique, :where, :type, :using, :opclasses].map do |option|
|
|
493
|
+
[option, index_def.public_send(option)] if index_def.respond_to?(option)
|
|
494
|
+
end.compact.to_h
|
|
495
|
+
|
|
496
|
+
@removed_indexes << IndexDefinition.new(table: table_name, **existing_options)
|
|
484
497
|
end
|
|
485
498
|
end
|
|
486
499
|
|
|
@@ -185,7 +185,7 @@ module OnlineMigrations
|
|
|
185
185
|
@small_tables = []
|
|
186
186
|
@check_down = false
|
|
187
187
|
@enabled_checks = @error_messages.keys.map { |k| [k, {}] }.to_h
|
|
188
|
-
@verbose_sql_logs = defined?(Rails) && Rails.env.production?
|
|
188
|
+
@verbose_sql_logs = defined?(Rails.env) && Rails.env.production?
|
|
189
189
|
end
|
|
190
190
|
|
|
191
191
|
def lock_retrier=(value)
|
|
@@ -262,17 +262,13 @@ module OnlineMigrations
|
|
|
262
262
|
private
|
|
263
263
|
def ensure_supports_multiple_dbs
|
|
264
264
|
unless Utils.supports_multiple_dbs?
|
|
265
|
-
raise "
|
|
265
|
+
raise "OnlineMigrations does not support multiple databases for Active Record < 6.1"
|
|
266
266
|
end
|
|
267
267
|
end
|
|
268
268
|
|
|
269
269
|
def db_config_name
|
|
270
270
|
connection = OnlineMigrations.current_migration.connection
|
|
271
|
-
|
|
272
|
-
connection.pool.spec.name
|
|
273
|
-
else
|
|
274
|
-
connection.pool.db_config.name
|
|
275
|
-
end
|
|
271
|
+
connection.pool.db_config.name
|
|
276
272
|
end
|
|
277
273
|
end
|
|
278
274
|
end
|
|
@@ -74,6 +74,16 @@ class <%= migration_name %> < <%= migration_parent %>
|
|
|
74
74
|
end
|
|
75
75
|
<% end %>",
|
|
76
76
|
|
|
77
|
+
add_column_with_default_null:
|
|
78
|
+
"Adding a column with a null default blocks reads and writes while the entire table is rewritten.
|
|
79
|
+
Instead, add the column without a default value.
|
|
80
|
+
|
|
81
|
+
class <%= migration_name %> < <%= migration_parent %>
|
|
82
|
+
def change
|
|
83
|
+
<%= code %>
|
|
84
|
+
end
|
|
85
|
+
end",
|
|
86
|
+
|
|
77
87
|
add_column_json:
|
|
78
88
|
"There's no equality operator for the json column type, which can cause errors for
|
|
79
89
|
existing SELECT DISTINCT queries in your application. Use jsonb instead.
|
|
@@ -30,10 +30,7 @@ module OnlineMigrations
|
|
|
30
30
|
return false if where != other.where
|
|
31
31
|
return false if other.respond_to?(:opclasses) && opclasses != other.opclasses
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
when [true, true]
|
|
35
|
-
columns == other.columns
|
|
36
|
-
when [true, false]
|
|
33
|
+
if unique && !other.unique
|
|
37
34
|
false
|
|
38
35
|
else
|
|
39
36
|
prefix?(self, other)
|
|
@@ -69,8 +69,9 @@ module OnlineMigrations
|
|
|
69
69
|
def renamed_tables
|
|
70
70
|
@renamed_tables ||= begin
|
|
71
71
|
table_renames = OnlineMigrations.config.table_renames
|
|
72
|
+
views = connection.views
|
|
72
73
|
table_renames.select do |old_name, _|
|
|
73
|
-
|
|
74
|
+
views.include?(old_name)
|
|
74
75
|
end
|
|
75
76
|
end
|
|
76
77
|
end
|
|
@@ -78,8 +79,9 @@ module OnlineMigrations
|
|
|
78
79
|
def renamed_columns
|
|
79
80
|
@renamed_columns ||= begin
|
|
80
81
|
column_renames = OnlineMigrations.config.column_renames
|
|
82
|
+
views = connection.views
|
|
81
83
|
column_renames.select do |table_name, _|
|
|
82
|
-
|
|
84
|
+
views.include?(table_name)
|
|
83
85
|
end
|
|
84
86
|
end
|
|
85
87
|
end
|
|
@@ -85,9 +85,13 @@ module OnlineMigrations
|
|
|
85
85
|
|
|
86
86
|
conditions = columns_and_values.map do |(column_name, value)|
|
|
87
87
|
value = Arel.sql(value.call.to_s) if value.is_a?(Proc)
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
|
|
89
|
+
# Ignore subqueries in conditions
|
|
90
|
+
unless value.is_a?(Arel::Nodes::SqlLiteral) && value.to_s =~ /select\s+/i
|
|
91
|
+
arel_column = model.arel_table[column_name]
|
|
92
|
+
arel_column.not_eq(value).or(arel_column.eq(nil))
|
|
93
|
+
end
|
|
94
|
+
end.compact
|
|
91
95
|
|
|
92
96
|
batch_relation = model.where(conditions.inject(:and))
|
|
93
97
|
batch_relation = yield batch_relation if block_given?
|
|
@@ -685,7 +689,18 @@ module OnlineMigrations
|
|
|
685
689
|
index_name = options[:name]
|
|
686
690
|
index_name ||= index_name(table_name, column_names)
|
|
687
691
|
|
|
688
|
-
|
|
692
|
+
index_exists =
|
|
693
|
+
if Utils.ar_version <= 5.0
|
|
694
|
+
# Older Active Record is unable to handle blank columns correctly in `index_exists?`,
|
|
695
|
+
# so we need to use `index_name_exists?`.
|
|
696
|
+
index_name_exists?(table_name, index_name, nil)
|
|
697
|
+
elsif Utils.ar_version <= 6.0
|
|
698
|
+
index_name_exists?(table_name, index_name)
|
|
699
|
+
else
|
|
700
|
+
index_exists?(table_name, column_names, **options)
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
if index_exists
|
|
689
704
|
disable_statement_timeout do
|
|
690
705
|
# "DROP INDEX CONCURRENTLY" requires a "SHARE UPDATE EXCLUSIVE" lock.
|
|
691
706
|
# It only conflicts with constraint validations, other creating/removing indexes,
|
|
@@ -820,6 +835,29 @@ module OnlineMigrations
|
|
|
820
835
|
end
|
|
821
836
|
end
|
|
822
837
|
|
|
838
|
+
# @private
|
|
839
|
+
def pk_and_sequence_for(table)
|
|
840
|
+
views = self.views
|
|
841
|
+
|
|
842
|
+
table_renames = OnlineMigrations.config.table_renames
|
|
843
|
+
renamed_tables = table_renames.select do |old_name, _|
|
|
844
|
+
views.include?(old_name)
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
column_renames = OnlineMigrations.config.column_renames
|
|
848
|
+
renamed_columns = column_renames.select do |table_name, _|
|
|
849
|
+
views.include?(table_name)
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
if renamed_tables.key?(table)
|
|
853
|
+
super(renamed_tables[table])
|
|
854
|
+
elsif renamed_columns.key?(table)
|
|
855
|
+
super("#{table}_column_rename")
|
|
856
|
+
else
|
|
857
|
+
super
|
|
858
|
+
end
|
|
859
|
+
end
|
|
860
|
+
|
|
823
861
|
# Disables statement timeout while executing &block
|
|
824
862
|
#
|
|
825
863
|
# Long-running migrations may take more than the timeout allowed by the database.
|
|
@@ -905,7 +943,7 @@ module OnlineMigrations
|
|
|
905
943
|
def __index_column_names(column_names)
|
|
906
944
|
if column_names.is_a?(String) && /\W/.match(column_names)
|
|
907
945
|
column_names
|
|
908
|
-
|
|
946
|
+
elsif column_names.present?
|
|
909
947
|
Array(column_names)
|
|
910
948
|
end
|
|
911
949
|
end
|
|
@@ -9,7 +9,7 @@ module OnlineMigrations
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def developer_env?
|
|
12
|
-
defined?(Rails) && (Rails.env.development? || Rails.env.test?)
|
|
12
|
+
defined?(Rails.env) && (Rails.env.development? || Rails.env.test?)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def say(message)
|
|
@@ -26,7 +26,9 @@ module OnlineMigrations
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def supports_multiple_dbs?
|
|
29
|
-
|
|
29
|
+
# Technically, Active Record 6.0+ supports multiple databases,
|
|
30
|
+
# but we can not get the database spec name for this version.
|
|
31
|
+
ar_version >= 6.1
|
|
30
32
|
end
|
|
31
33
|
|
|
32
34
|
def migration_parent
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: online_migrations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fatkodima
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2022-
|
|
11
|
+
date: 2022-11-10 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activerecord
|
|
@@ -101,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
102
|
version: '0'
|
|
103
103
|
requirements: []
|
|
104
|
-
rubygems_version: 3.
|
|
104
|
+
rubygems_version: 3.1.6
|
|
105
105
|
signing_key:
|
|
106
106
|
specification_version: 4
|
|
107
107
|
summary: Catch unsafe PostgreSQL migrations in development and run them easier in
|