online_migrations 0.33.2 → 0.35.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 -1
- data/README.md +2 -2
- data/lib/generators/online_migrations/upgrade_generator.rb +1 -1
- data/lib/online_migrations/background_data_migrations/migration.rb +18 -3
- data/lib/online_migrations/background_data_migrations/migration_helpers.rb +12 -3
- data/lib/online_migrations/background_data_migrations/scheduler.rb +12 -1
- data/lib/online_migrations/background_schema_migrations/migration.rb +2 -6
- data/lib/online_migrations/background_schema_migrations/migration_helpers.rb +13 -6
- data/lib/online_migrations/change_column_type_helpers.rb +10 -5
- data/lib/online_migrations/command_checker.rb +17 -10
- data/lib/online_migrations/command_recorder.rb +1 -1
- data/lib/online_migrations/data_migration.rb +2 -1
- data/lib/online_migrations/index_definition.rb +5 -4
- data/lib/online_migrations/migration.rb +1 -1
- data/lib/online_migrations/schema_cache.rb +0 -77
- data/lib/online_migrations/schema_statements.rb +4 -9
- data/lib/online_migrations/utils.rb +1 -1
- data/lib/online_migrations/version.rb +1 -1
- data/lib/online_migrations.rb +1 -6
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5a84bdeb495a3d25432c6ae97d4c46777517ae3bbcf01359020d400ad8f16f30
|
|
4
|
+
data.tar.gz: 935d3b38b096fcdb222a89065d7c10023a8b85a6009065d73a1df9bb92c2b0f8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f2c578a25081bb86cafc2851cb818c40e819363d40bdac2a6f4cde634f71a8dc3a90909e4dbf10bf0fb6df61e1d979f4d581982650eec3834715baa8e5888832
|
|
7
|
+
data.tar.gz: 01377b6bcdbe0b601a45b53a52a99746e443d60c5ca513e2312322c81718e4a995fde32ee78a45554fe155878391f6a885fdef50bdea4d4619a4e10799bab295
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
## master (unreleased)
|
|
2
2
|
|
|
3
|
+
## 0.35.0 (2026-07-01)
|
|
4
|
+
|
|
5
|
+
- Drop support for Ruby < 3.3
|
|
6
|
+
- Defer `tick_total` calculation to the background data migration starting time instead of enqueueing time
|
|
7
|
+
- Make "replacing an index" check independent of the live database state
|
|
8
|
+
|
|
9
|
+
## 0.34.0 (2026-05-29)
|
|
10
|
+
|
|
11
|
+
- Drop support for Rails < 7.2
|
|
12
|
+
|
|
13
|
+
- Do not schedule background data migrations with non existent data migration classes
|
|
14
|
+
|
|
15
|
+
This prevents a situation when the background data migration was enqueued and started running
|
|
16
|
+
before the deploy completes and the data migration class is available.
|
|
17
|
+
|
|
18
|
+
- Add ability to enqueue background migrations for specific shards (if using sharding)
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
add_index_in_background(:users, :name, connection_class_name: "ApplicationRecord", shard: :shard_one)
|
|
22
|
+
enqueue_background_data_migration("MyMigration", shard: :shard_one)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- Fix validating foreign key in `add_reference_concurrently` when multiple foreign keys target the same table
|
|
26
|
+
|
|
3
27
|
## 0.33.2 (2026-03-16)
|
|
4
28
|
|
|
5
29
|
- Fix message for adding to `ignored_columns` when renaming a column
|
|
@@ -22,7 +46,7 @@
|
|
|
22
46
|
- Add ability to create delayed background migrations
|
|
23
47
|
|
|
24
48
|
```ruby
|
|
25
|
-
add_index_in_background(:users, :name, delay: true)
|
|
49
|
+
add_index_in_background(:users, :name, connection_class_name: "ApplicationRecord", delay: true)
|
|
26
50
|
enqueue_background_data_migration("MyMigration", delay: true)
|
|
27
51
|
```
|
|
28
52
|
|
data/README.md
CHANGED
|
@@ -16,8 +16,8 @@ See [comparison to `strong_migrations`](#comparison-to-strong_migrations)
|
|
|
16
16
|
|
|
17
17
|
## Requirements
|
|
18
18
|
|
|
19
|
-
- Ruby 3.
|
|
20
|
-
- Rails 7.
|
|
19
|
+
- Ruby 3.3+
|
|
20
|
+
- Rails 7.2+
|
|
21
21
|
- PostgreSQL 12+
|
|
22
22
|
|
|
23
23
|
For older Ruby and Rails versions you can use older versions of this gem.
|
|
@@ -48,7 +48,7 @@ module OnlineMigrations
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
iteration_pause_column = connection.columns(:background_data_migrations).find { |c| c.name == "iteration_pause" }
|
|
51
|
-
if iteration_pause_column
|
|
51
|
+
if iteration_pause_column&.default
|
|
52
52
|
migrations << "background_data_migrations_remove_iteration_pause_default"
|
|
53
53
|
end
|
|
54
54
|
|
|
@@ -123,7 +123,13 @@ module OnlineMigrations
|
|
|
123
123
|
# @private
|
|
124
124
|
def start
|
|
125
125
|
if enqueued?
|
|
126
|
-
|
|
126
|
+
# Defer `tick_total` calculation to the migration starting time
|
|
127
|
+
# instead of the enqueueing time to avoid failed deploys.
|
|
128
|
+
self.tick_total ||= safely_calculate_tick_total
|
|
129
|
+
self.status = :running
|
|
130
|
+
self.started_at = Time.current
|
|
131
|
+
save!
|
|
132
|
+
|
|
127
133
|
data_migration.after_start
|
|
128
134
|
true
|
|
129
135
|
else
|
|
@@ -309,11 +315,20 @@ module OnlineMigrations
|
|
|
309
315
|
def set_defaults
|
|
310
316
|
config = ::OnlineMigrations.config.background_data_migrations
|
|
311
317
|
self.max_attempts ||= config.max_attempts
|
|
312
|
-
self.
|
|
318
|
+
self.iteration_pause ||= config.iteration_pause
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def safely_calculate_tick_total
|
|
322
|
+
on_shard_if_present do
|
|
313
323
|
data_migration.count
|
|
314
324
|
end
|
|
325
|
+
rescue ActiveRecord::QueryCanceled => e
|
|
326
|
+
OnlineMigrations.config.background_data_migrations.error_handler.call(e, self)
|
|
315
327
|
|
|
316
|
-
|
|
328
|
+
# `tick_total` is not required and is used only for progress tracking.
|
|
329
|
+
# Probably the `count` method was implemented in a non-efficient way.
|
|
330
|
+
# Better to not track progress than have a failing migration.
|
|
331
|
+
nil
|
|
317
332
|
end
|
|
318
333
|
|
|
319
334
|
def instrument_status_change
|
|
@@ -339,6 +339,7 @@ module OnlineMigrations
|
|
|
339
339
|
# @param migration_name [String, Class] Background migration class name
|
|
340
340
|
# @param arguments [Array] Extra arguments to pass to the migration instance when the migration runs
|
|
341
341
|
# @param delay [Boolean] Whether this migration should be delayed and approved by the user to start running.
|
|
342
|
+
# @param shard [String, Symbol] Specific shard this migration will be enqueued for. Defaults to all shards.
|
|
342
343
|
# @option options [Integer] :max_attempts (5) Maximum number of batch run attempts
|
|
343
344
|
# @option options [String, nil] :connection_class_name Class name to use to get connections
|
|
344
345
|
#
|
|
@@ -369,7 +370,7 @@ module OnlineMigrations
|
|
|
369
370
|
# @note For convenience, the enqueued background data migration is run inline
|
|
370
371
|
# in development and test environments
|
|
371
372
|
#
|
|
372
|
-
def enqueue_background_data_migration(migration_name, *arguments, delay: false, **options)
|
|
373
|
+
def enqueue_background_data_migration(migration_name, *arguments, delay: false, shard: nil, **options)
|
|
373
374
|
options.assert_valid_keys(:max_attempts, :iteration_pause, :connection_class_name)
|
|
374
375
|
|
|
375
376
|
migration_name = migration_name.name if migration_name.is_a?(Class)
|
|
@@ -380,8 +381,16 @@ module OnlineMigrations
|
|
|
380
381
|
end
|
|
381
382
|
|
|
382
383
|
connection_class = options[:connection_class_name].constantize
|
|
383
|
-
shards = Utils.shard_names(connection_class)
|
|
384
|
-
|
|
384
|
+
shards = Utils.shard_names(connection_class).map(&:to_s)
|
|
385
|
+
if shards.size == 1
|
|
386
|
+
shards = [nil]
|
|
387
|
+
elsif shard
|
|
388
|
+
shard = shard.to_s
|
|
389
|
+
raise "Unknown shard: #{shard}" if !shards.include?(shard)
|
|
390
|
+
|
|
391
|
+
shards = [shard]
|
|
392
|
+
end
|
|
393
|
+
|
|
385
394
|
status = delay ? :delayed : :pending
|
|
386
395
|
|
|
387
396
|
shards.each do |shard|
|
|
@@ -37,7 +37,7 @@ module OnlineMigrations
|
|
|
37
37
|
|
|
38
38
|
with_lock do
|
|
39
39
|
stuck_migrations, active_migrations = relation.running.partition(&:stuck?)
|
|
40
|
-
runnable_migrations = relation.pending + stuck_migrations
|
|
40
|
+
runnable_migrations = migrations_with_existing_classes(relation.pending) + stuck_migrations
|
|
41
41
|
|
|
42
42
|
# Ensure no more than 'concurrency' migrations are running at the same time.
|
|
43
43
|
remaining_to_enqueue = concurrency - active_migrations.count
|
|
@@ -71,6 +71,17 @@ module OnlineMigrations
|
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
def migrations_with_existing_classes(migrations)
|
|
75
|
+
migrations.select do |migration|
|
|
76
|
+
# Detect if the data migration class exists.
|
|
77
|
+
# It may not yet exist if the data migration was enqueued before the deploy finished.
|
|
78
|
+
migration.data_migration
|
|
79
|
+
true
|
|
80
|
+
rescue DataMigration::NotFoundError
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
74
85
|
def enqueue_migration(migration)
|
|
75
86
|
job = OnlineMigrations.config.background_data_migrations.job
|
|
76
87
|
job_class = job.constantize
|
|
@@ -208,12 +208,8 @@ module OnlineMigrations
|
|
|
208
208
|
|
|
209
209
|
# Extension point, do not remove this method.
|
|
210
210
|
def with_connection(&block)
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
connection_class.with_connection(&block)
|
|
214
|
-
else
|
|
215
|
-
yield connection_class.connection
|
|
216
|
-
end
|
|
211
|
+
# https://github.com/rails/rails/pull/51083
|
|
212
|
+
connection_class.with_connection(&block)
|
|
217
213
|
end
|
|
218
214
|
|
|
219
215
|
def with_statement_timeout(connection, timeout)
|
|
@@ -4,7 +4,7 @@ module OnlineMigrations
|
|
|
4
4
|
module BackgroundSchemaMigrations
|
|
5
5
|
module MigrationHelpers
|
|
6
6
|
def add_index_in_background(table_name, column_name, **options)
|
|
7
|
-
migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name, :delay)
|
|
7
|
+
migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name, :delay, :shard)
|
|
8
8
|
|
|
9
9
|
options[:algorithm] = :concurrently
|
|
10
10
|
index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)
|
|
@@ -34,7 +34,7 @@ module OnlineMigrations
|
|
|
34
34
|
def remove_index_in_background(table_name, column_name = nil, name:, **options)
|
|
35
35
|
raise ArgumentError, "Index name must be specified" if name.blank?
|
|
36
36
|
|
|
37
|
-
migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name, :delay)
|
|
37
|
+
migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name, :delay, :shard)
|
|
38
38
|
|
|
39
39
|
if !index_exists?(table_name, column_name, **options, name: name)
|
|
40
40
|
Utils.raise_or_say("Index deletion was not enqueued because the index does not exist.")
|
|
@@ -46,7 +46,7 @@ module OnlineMigrations
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def validate_foreign_key_in_background(from_table, to_table = nil, **options)
|
|
49
|
-
migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name, :delay)
|
|
49
|
+
migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name, :delay, :shard)
|
|
50
50
|
|
|
51
51
|
if !foreign_key_exists?(from_table, to_table, **options)
|
|
52
52
|
Utils.raise_or_say("Foreign key validation was not enqueued because the foreign key does not exist.")
|
|
@@ -87,7 +87,7 @@ module OnlineMigrations
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
def enqueue_background_schema_migration(migration_name, table_name, connection_class_name: nil, delay: false, **options)
|
|
90
|
+
def enqueue_background_schema_migration(migration_name, table_name, connection_class_name: nil, delay: false, shard: nil, **options)
|
|
91
91
|
options.assert_valid_keys(:definition, :max_attempts, :statement_timeout)
|
|
92
92
|
|
|
93
93
|
if Utils.multiple_databases? && !connection_class_name
|
|
@@ -104,8 +104,15 @@ module OnlineMigrations
|
|
|
104
104
|
# Normalize to the real connection class name.
|
|
105
105
|
connection_class_name = connection_class.name
|
|
106
106
|
|
|
107
|
-
shards = Utils.shard_names(connection_class)
|
|
108
|
-
|
|
107
|
+
shards = Utils.shard_names(connection_class).map(&:to_s)
|
|
108
|
+
if shards.size == 1
|
|
109
|
+
shards = [nil]
|
|
110
|
+
elsif shard
|
|
111
|
+
shard = shard.to_s
|
|
112
|
+
raise "Unknown shard: #{shard}" if !shards.include?(shard)
|
|
113
|
+
|
|
114
|
+
shards = [shard]
|
|
115
|
+
end
|
|
109
116
|
|
|
110
117
|
status = delay ? :delayed : :pending
|
|
111
118
|
|
|
@@ -212,7 +212,14 @@ module OnlineMigrations
|
|
|
212
212
|
conversions = column_names.map do |column_name|
|
|
213
213
|
tmp_column = __change_type_column(column_name)
|
|
214
214
|
|
|
215
|
-
old_value =
|
|
215
|
+
old_value = begin
|
|
216
|
+
# Delete after supporting only ActiveRecord >= 8.2
|
|
217
|
+
Arel::Table.new(table_name)[column_name]
|
|
218
|
+
rescue ArgumentError
|
|
219
|
+
# https://github.com/rails/rails/commit/b1650993b02497ae7d0d8b984d40bc036e62c681
|
|
220
|
+
Arel::Table.new(name: table_name)[column_name]
|
|
221
|
+
end
|
|
222
|
+
|
|
216
223
|
if (type_cast_function = type_cast_functions.with_indifferent_access[column_name])
|
|
217
224
|
old_value =
|
|
218
225
|
case type_cast_function
|
|
@@ -393,10 +400,8 @@ module OnlineMigrations
|
|
|
393
400
|
def __options_from_column(column, options)
|
|
394
401
|
result = {}
|
|
395
402
|
options.each do |option|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
result[option] = value if !value.nil?
|
|
399
|
-
end
|
|
403
|
+
value = column.public_send(option)
|
|
404
|
+
result[option] = value if !value.nil?
|
|
400
405
|
end
|
|
401
406
|
result
|
|
402
407
|
end
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "erb"
|
|
4
|
-
require "set"
|
|
5
4
|
|
|
6
5
|
module OnlineMigrations
|
|
7
6
|
# @private
|
|
@@ -46,7 +45,7 @@ module OnlineMigrations
|
|
|
46
45
|
|
|
47
46
|
true
|
|
48
47
|
end
|
|
49
|
-
ruby2_keywords(:check)
|
|
48
|
+
ruby2_keywords(:check)
|
|
50
49
|
|
|
51
50
|
def version_safe?
|
|
52
51
|
version && version <= OnlineMigrations.config.start_after
|
|
@@ -574,13 +573,21 @@ module OnlineMigrations
|
|
|
574
573
|
Array(index.columns).map(&:to_s) == Array(options[:column]).map(&:to_s)
|
|
575
574
|
end
|
|
576
575
|
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
[option, index_def.public_send(option)] if index_def.respond_to?(option)
|
|
580
|
-
end.to_h
|
|
576
|
+
# IndexDefinition expects "columns", but "remove_index" API uses "column".
|
|
577
|
+
options[:columns] = options[:column]
|
|
581
578
|
|
|
582
|
-
|
|
583
|
-
|
|
579
|
+
# Fall back to the declared options when the index isn't present in the database,
|
|
580
|
+
# so an index remove → add is still recorded and caught.
|
|
581
|
+
existing_options =
|
|
582
|
+
[:name, :columns, :unique, :where, :type, :using, :opclasses].index_with do |option|
|
|
583
|
+
if index_def
|
|
584
|
+
index_def.public_send(option)
|
|
585
|
+
else
|
|
586
|
+
options[option]
|
|
587
|
+
end
|
|
588
|
+
end.compact
|
|
589
|
+
|
|
590
|
+
@removed_indexes << IndexDefinition.new(table: table_name, **existing_options)
|
|
584
591
|
end
|
|
585
592
|
|
|
586
593
|
def add_foreign_key(from_table, to_table, **options)
|
|
@@ -844,8 +851,8 @@ module OnlineMigrations
|
|
|
844
851
|
|
|
845
852
|
def index_include_column?(index, column)
|
|
846
853
|
index.columns.include?(column) ||
|
|
847
|
-
|
|
848
|
-
|
|
854
|
+
index.include&.include?(column) ||
|
|
855
|
+
index.where&.include?(column)
|
|
849
856
|
end
|
|
850
857
|
|
|
851
858
|
def run_custom_checks(method, args)
|
|
@@ -16,6 +16,7 @@ module OnlineMigrations
|
|
|
16
16
|
# @return [DataMigration] the Data Migration with the given name.
|
|
17
17
|
#
|
|
18
18
|
# @raise [NotFoundError] if a Data Migration with the given name does not exist.
|
|
19
|
+
# @raise [ArgumentError] if a Data Migration with the given name is not a subclass of DataMigration.
|
|
19
20
|
#
|
|
20
21
|
def named(name)
|
|
21
22
|
namespace = OnlineMigrations.config.background_data_migrations.migrations_module.constantize
|
|
@@ -26,7 +27,7 @@ module OnlineMigrations
|
|
|
26
27
|
|
|
27
28
|
raise NotFoundError.new("Data Migration #{name} not found", name) if migration.nil?
|
|
28
29
|
if !(migration.is_a?(Class) && migration < self)
|
|
29
|
-
raise
|
|
30
|
+
raise ArgumentError, "#{name} is not a Data Migration"
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
migration
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
module OnlineMigrations
|
|
4
4
|
# @private
|
|
5
5
|
class IndexDefinition
|
|
6
|
-
attr_reader :table, :columns, :unique, :opclasses, :where, :type, :using
|
|
6
|
+
attr_reader :table, :name, :columns, :unique, :opclasses, :where, :type, :using
|
|
7
7
|
|
|
8
8
|
def initialize(**options)
|
|
9
|
-
@table = options[:table]
|
|
9
|
+
@table = options[:table]&.to_s
|
|
10
|
+
@name = options[:name]&.to_s
|
|
10
11
|
@columns = Array(options[:columns]).map(&:to_s)
|
|
11
12
|
@unique = options[:unique]
|
|
12
13
|
@opclasses = options[:opclass] || {}
|
|
@@ -20,7 +21,7 @@ module OnlineMigrations
|
|
|
20
21
|
# For ActiveRecord::ConnectionAdapters::IndexDefinition is for expression indexes,
|
|
21
22
|
# `columns` is a string
|
|
22
23
|
table == other.table &&
|
|
23
|
-
columns.intersect?(Array(other.columns))
|
|
24
|
+
((name && name == other.name) || columns.intersect?(Array(other.columns)))
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
# @param other [OnlineMigrations::IndexDefinition, ActiveRecord::ConnectionAdapters::IndexDefinition]
|
|
@@ -28,7 +29,7 @@ module OnlineMigrations
|
|
|
28
29
|
return false if type != other.type
|
|
29
30
|
return false if using != other.using
|
|
30
31
|
return false if where != other.where
|
|
31
|
-
return false if
|
|
32
|
+
return false if opclasses != other.opclasses
|
|
32
33
|
|
|
33
34
|
if unique && !other.unique
|
|
34
35
|
false
|
|
@@ -3,83 +3,6 @@
|
|
|
3
3
|
module OnlineMigrations
|
|
4
4
|
# @private
|
|
5
5
|
module SchemaCache
|
|
6
|
-
def primary_keys(connection, table_name)
|
|
7
|
-
if (renamed_table = renamed_table?(connection, table_name))
|
|
8
|
-
super(connection, renamed_table)
|
|
9
|
-
elsif renamed_column?(connection, table_name)
|
|
10
|
-
super(connection, column_rename_table(table_name))
|
|
11
|
-
else
|
|
12
|
-
super
|
|
13
|
-
end
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def columns(connection, table_name)
|
|
17
|
-
if (renamed_table = renamed_table?(connection, table_name))
|
|
18
|
-
super(connection, renamed_table)
|
|
19
|
-
elsif renamed_column?(connection, table_name)
|
|
20
|
-
columns = super(connection, column_rename_table(table_name))
|
|
21
|
-
OnlineMigrations.config.column_renames[table_name].each do |old_column_name, new_column_name|
|
|
22
|
-
duplicate_column(old_column_name, new_column_name, columns)
|
|
23
|
-
end
|
|
24
|
-
columns
|
|
25
|
-
else
|
|
26
|
-
super.reject { |column| column.name.end_with?("_for_type_change") }
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
def indexes(connection, table_name)
|
|
31
|
-
if (renamed_table = renamed_table?(connection, table_name))
|
|
32
|
-
super(connection, renamed_table)
|
|
33
|
-
elsif renamed_column?(connection, table_name)
|
|
34
|
-
super(connection, column_rename_table(table_name))
|
|
35
|
-
else
|
|
36
|
-
super
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def clear_data_source_cache!(connection, name)
|
|
41
|
-
if (renamed_table = renamed_table?(connection, name))
|
|
42
|
-
super(connection, renamed_table)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
if renamed_column?(connection, name)
|
|
46
|
-
super(connection, column_rename_table(name))
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
super
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
private
|
|
53
|
-
def renamed_table?(connection, table_name)
|
|
54
|
-
table_renames = OnlineMigrations.config.table_renames
|
|
55
|
-
if table_renames.key?(table_name) && connection.view_exists?(table_name)
|
|
56
|
-
table_renames[table_name]
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def renamed_column?(connection, table_name)
|
|
61
|
-
column_renames = OnlineMigrations.config.column_renames
|
|
62
|
-
column_renames.key?(table_name) && connection.view_exists?(table_name)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def column_rename_table(table_name)
|
|
66
|
-
"#{table_name}_column_rename"
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def duplicate_column(old_column_name, new_column_name, columns)
|
|
70
|
-
old_column = columns.find { |column| column.name == old_column_name }
|
|
71
|
-
new_column = old_column.dup
|
|
72
|
-
# Active Record defines only reader for :name
|
|
73
|
-
new_column.instance_variable_set(:@name, new_column_name)
|
|
74
|
-
# Correspond to the Active Record freezing of each column
|
|
75
|
-
columns << new_column.freeze
|
|
76
|
-
end
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
# @private
|
|
80
|
-
module SchemaCache72
|
|
81
|
-
# Active Record >= 7.2 changed signature of the methods,
|
|
82
|
-
# see https://github.com/rails/rails/pull/48716.
|
|
83
6
|
def primary_keys(pool, table_name)
|
|
84
7
|
if (renamed_table = renamed_table?(pool, table_name))
|
|
85
8
|
super(pool, renamed_table)
|
|
@@ -111,7 +111,7 @@ module OnlineMigrations
|
|
|
111
111
|
|
|
112
112
|
relation.update_all(updates)
|
|
113
113
|
|
|
114
|
-
progress.call(relation) if progress
|
|
114
|
+
progress.call(relation) if progress.present?
|
|
115
115
|
|
|
116
116
|
sleep(pause_ms * 0.001) if pause_ms > 0
|
|
117
117
|
end
|
|
@@ -635,7 +635,7 @@ module OnlineMigrations
|
|
|
635
635
|
# @see https://api.rubyonrails.org/v8.1/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_column
|
|
636
636
|
#
|
|
637
637
|
def add_column(table_name, column_name, type, **options)
|
|
638
|
-
if column_exists?(table_name, column_name
|
|
638
|
+
if column_exists?(table_name, column_name)
|
|
639
639
|
Utils.say("Column was not added because it already exists (this may be due to an aborted migration " \
|
|
640
640
|
"or similar) table_name: #{table_name}, column_name: #{column_name}")
|
|
641
641
|
else
|
|
@@ -705,7 +705,7 @@ module OnlineMigrations
|
|
|
705
705
|
add_foreign_key(table_name, foreign_table_name, **foreign_key, column: column_name, validate: false)
|
|
706
706
|
|
|
707
707
|
if foreign_key[:validate] != false
|
|
708
|
-
validate_foreign_key(table_name, foreign_table_name, **foreign_key)
|
|
708
|
+
validate_foreign_key(table_name, foreign_table_name, **foreign_key, column: column_name)
|
|
709
709
|
end
|
|
710
710
|
end
|
|
711
711
|
end
|
|
@@ -992,12 +992,7 @@ module OnlineMigrations
|
|
|
992
992
|
|
|
993
993
|
def __tmp_table_name_for_column_rename(table_name)
|
|
994
994
|
suffix = "_column_rename"
|
|
995
|
-
|
|
996
|
-
# On ActiveRecord 7.1 can use table_name_length instead of max_identifier_length,
|
|
997
|
-
# see https://github.com/rails/rails/pull/45136.
|
|
998
|
-
# Also we need to account for "_pkey", because older versions does not correctly rename
|
|
999
|
-
# tables with long names. Remove when supporting newer versions only.
|
|
1000
|
-
prefix_length = max_identifier_length - "_pkey".size - suffix.length
|
|
995
|
+
prefix_length = max_identifier_length - suffix.length
|
|
1001
996
|
table_name[0, prefix_length] + suffix
|
|
1002
997
|
end
|
|
1003
998
|
end
|
data/lib/online_migrations.rb
CHANGED
|
@@ -116,16 +116,11 @@ module OnlineMigrations
|
|
|
116
116
|
ActiveRecord::Migration.prepend(OnlineMigrations::Migration)
|
|
117
117
|
ActiveRecord::Migrator.prepend(OnlineMigrations::Migrator)
|
|
118
118
|
ActiveRecord::SchemaDumper.prepend(OnlineMigrations::SchemaDumper)
|
|
119
|
+
ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache)
|
|
119
120
|
|
|
120
121
|
ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(OnlineMigrations::DatabaseTasks)
|
|
121
122
|
ActiveRecord::Migration::CommandRecorder.include(OnlineMigrations::CommandRecorder)
|
|
122
123
|
|
|
123
|
-
if OnlineMigrations::Utils.ar_version >= 7.2
|
|
124
|
-
ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache72)
|
|
125
|
-
else
|
|
126
|
-
ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
124
|
if !ActiveRecord::Batches::BatchEnumerator.method_defined?(:use_ranges)
|
|
130
125
|
ActiveRecord::Batches::BatchEnumerator.include(OnlineMigrations::ActiveRecordBatchEnumerator)
|
|
131
126
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: online_migrations
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.35.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- fatkodima
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '7.
|
|
18
|
+
version: '7.2'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '7.
|
|
25
|
+
version: '7.2'
|
|
26
26
|
email:
|
|
27
27
|
- fatkodima123@gmail.com
|
|
28
28
|
executables: []
|
|
@@ -108,14 +108,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
108
108
|
requirements:
|
|
109
109
|
- - ">="
|
|
110
110
|
- !ruby/object:Gem::Version
|
|
111
|
-
version: '3.
|
|
111
|
+
version: '3.3'
|
|
112
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
113
|
requirements:
|
|
114
114
|
- - ">="
|
|
115
115
|
- !ruby/object:Gem::Version
|
|
116
116
|
version: '0'
|
|
117
117
|
requirements: []
|
|
118
|
-
rubygems_version: 4.0.
|
|
118
|
+
rubygems_version: 4.0.14
|
|
119
119
|
specification_version: 4
|
|
120
120
|
summary: Catch unsafe PostgreSQL migrations in development and run them easier in
|
|
121
121
|
production
|