online_migrations 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 296a1517b032cbd6d5fa3948f60f1a4f20c4142c8f4c7676c43998f9e941925d
4
- data.tar.gz: f61a7c6728a6ea1e834be61187b61e3ddf004f4314003752ec3ccf9a5b79afd9
3
+ metadata.gz: 2b1b826df875fae97622c702205853da01d67153172ef73fbb0edf28a2f7ff60
4
+ data.tar.gz: 18ae161255543e7ab7c266efc94f1ca166a344aa18b92dd4ab2f37209fb42547
5
5
  SHA512:
6
- metadata.gz: fd04da6b57f9862726ee45e6ed13b1032632099a089e26e691717b2e93009269b7f8a8cf3c828501ef97a86d3d13731d4cadb77d0b48f0cf25fea172502780c1
7
- data.tar.gz: '089a7f40afc28b9671669764ee98c760e4ee8649aab67a4d814b22ca8f5c52cf76afc8a5c9f95244d8be7b879d2b714fa38f07fff3c741bcc91e450077c96801'
6
+ metadata.gz: 705e4ce816bd8b4fcbcb78871589274bdf37acca01fbdf031883e87403a403782d28990ebed10acdf57adcbf3fb4e30e1dbf187123029bf6b1b7d31f26ccd3ca
7
+ data.tar.gz: 60ea354440b96645c5c03345d60793a66ba61d8aa1b946737098bc1449ba67e0b24caeb4581c525b3b014c5dd44b0ac28e0c539c8e3454ad67a3a1610cffdd79
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  ## master (unreleased)
2
2
 
3
+ ## 0.15.0 (2024-03-19)
4
+
5
+ - Reraise errors when running background migrations inline
6
+ - Add `remove_background_migration` migration helper
7
+ - Allow adding bigint foreign keys referencing integer primary keys
8
+ - Fix `add_reference_concurrently` to check for mismatched key types
9
+
10
+ ## 0.14.1 (2024-02-21)
11
+
12
+ - Fix `MigrationRunner` to consider `run_background_migrations_inline` proc
13
+
3
14
  ## 0.14.0 (2024-02-01)
4
15
 
5
16
  - Add ability to configure whether background migrations should be run inline
data/README.md CHANGED
@@ -191,7 +191,7 @@ end
191
191
 
192
192
  ```ruby
193
193
  class User < ApplicationRecord
194
- self.ignored_columns = ["name"]
194
+ self.ignored_columns += ["name"]
195
195
  end
196
196
  ```
197
197
 
@@ -206,7 +206,7 @@ end
206
206
  end
207
207
  ```
208
208
 
209
- 4. Remove column ignoring from `User` model
209
+ 4. Remove column ignoring from step 1
210
210
  5. Deploy
211
211
 
212
212
  ### Adding a column with a default value
@@ -488,7 +488,7 @@ It will use a combination of a VIEW and column aliasing to work with both column
488
488
 
489
489
  ```ruby
490
490
  class User < ApplicationRecord
491
- self.ignored_columns = ["name"]
491
+ self.ignored_columns += ["name"]
492
492
  end
493
493
  ```
494
494
 
@@ -1172,7 +1172,7 @@ A safer approach is to:
1172
1172
 
1173
1173
  ```ruby
1174
1174
  class User < ApplicationRecord
1175
- self.ignored_columns = ["type"]
1175
+ self.ignored_columns += ["type"]
1176
1176
  end
1177
1177
  ```
1178
1178
 
@@ -30,7 +30,8 @@ A generator is provided to create background migrations. Generate a new backgrou
30
30
  $ bin/rails generate online_migrations:background_migration backfill_project_issues_count
31
31
  ```
32
32
 
33
- This creates the background migration file `lib/online_migrations/background_migrations/backfill_project_issues_count.rb`.
33
+ This creates the background migration file `lib/online_migrations/background_migrations/backfill_project_issues_count.rb`
34
+ and the regular migration file `db/migrate/xxxxxxxxxxxxxx_enqueue_backfill_project_issues_count.rb` where we enqueue it.
34
35
 
35
36
  The generated class is a subclass of `OnlineMigrations::BackgroundMigration` that implements:
36
37
 
@@ -76,12 +77,16 @@ end
76
77
  You can enqueue your background migration to be run by the scheduler via:
77
78
 
78
79
  ```ruby
79
- # db/migrate/xxxxxxxxxxxxxx_backfill_project_issues_count.rb
80
- # ...
81
- def up
82
- enqueue_background_migration("BackfillProjectIssuesCount")
80
+ # db/migrate/xxxxxxxxxxxxxx_enqueue_backfill_project_issues_count.rb
81
+ class EnqueueBackfillProjectIssuesCount < ActiveRecord::Migration[7.1]
82
+ def up
83
+ enqueue_background_migration("BackfillProjectIssuesCount")
84
+ end
85
+
86
+ def down
87
+ remove_background_migration("BackfillProjectIssuesCount")
88
+ end
83
89
  end
84
- # ...
85
90
  ```
86
91
 
87
92
  `enqueue_background_migration` accepts additional configuration options which controls how the background migration is run. Check the [source code](https://github.com/fatkodima/online_migrations/blob/master/lib/online_migrations/background_migrations/migration_helpers.rb) for the list of all available configuration options.
@@ -106,7 +111,17 @@ end
106
111
  And pass them when enqueuing:
107
112
 
108
113
  ```ruby
109
- enqueue_background_migration("MyMigrationWithArgs", arg1, arg2, ...)
114
+ def up
115
+ enqueue_background_migration("MyMigrationWithArgs", arg1, arg2, ...)
116
+ end
117
+ ```
118
+
119
+ Make sure to also pass the arguments inside the `down` method of the migration:
120
+
121
+ ```ruby
122
+ def down
123
+ remove_background_migration("MyMigrationWithArgs", arg1, arg2, ...)
124
+ end
110
125
  ```
111
126
 
112
127
  ## Considerations when writing Background Migrations
data/docs/configuring.md CHANGED
@@ -101,13 +101,15 @@ config.lock_retrier = OnlineMigrations::ExponentialLockRetrier.new(
101
101
  )
102
102
  ```
103
103
 
104
- When statement within transaction fails - the whole transaction is retried.
104
+ When a statement within transaction fails - the whole transaction is retried. If any statement fails when running outside a transaction (e.g. using `disable_ddl_transaction!`) then only that statement is retried.
105
105
 
106
- To permanently disable lock retries, you can set `lock_retrier` to `nil`.
106
+ **Note**: Statements are retried by default, unless lock retries are disabled. It is possible to implement more sophisticated lock retriers. See [source code](https://github.com/fatkodima/online_migrations/blob/master/lib/online_migrations/lock_retrier.rb) for the examples.
107
107
 
108
108
  To temporarily disable lock retries while running migrations, set `DISABLE_LOCK_RETRIES` env variable. This is useful when you are deploying a hotfix and do not want to wait too long while the lock retrier safely tries to acquire the lock, but try to acquire the lock immediately with the default configured lock timeout value.
109
109
 
110
- **Note**: Statements are retried by default, unless lock retries are disabled. It is possible to implement more sophisticated lock retriers. See [source code](https://github.com/fatkodima/online_migrations/blob/master/lib/online_migrations/lock_retrier.rb) for the examples.
110
+ To permanently disable lock retries, you can set `lock_retrier` to `nil`.
111
+
112
+ Finally, if your lock retrier implementation does not have an explicit `lock_timeout` value configured, then the timeout behavior will fallback to the database configuration (`config/database.yml`) or the PostgreSQL server config value ([off by default](https://www.postgresql.org/docs/current/runtime-config-client.html#GUC-LOCK-TIMEOUT)). Take care configuring this value, as this fallback may result in your migrations running without a lock timeout!
111
113
 
112
114
  ## Existing Migrations
113
115
 
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rails/generators"
4
+ require "rails/generators/active_record/migration"
4
5
 
5
6
  module OnlineMigrations
6
7
  # @private
7
8
  class BackgroundMigrationGenerator < Rails::Generators::NamedBase
9
+ include ActiveRecord::Generators::Migration
10
+
8
11
  source_root File.expand_path("templates", __dir__)
9
- desc "This generator creates a background migration file."
12
+ desc "This generator creates a background migration related files."
10
13
 
11
14
  def create_background_migration_file
12
15
  migrations_module_file_path = migrations_module.underscore
@@ -20,6 +23,10 @@ module OnlineMigrations
20
23
  template("background_migration.rb", template_file)
21
24
  end
22
25
 
26
+ def create_migration_file
27
+ migration_template("migration.rb", File.join(db_migrate_path, "enqueue_#{file_name}.rb"))
28
+ end
29
+
23
30
  private
24
31
  def migrations_module
25
32
  config.migrations_module
@@ -28,5 +35,9 @@ module OnlineMigrations
28
35
  def config
29
36
  OnlineMigrations.config.background_migrations
30
37
  end
38
+
39
+ def migration_parent
40
+ "ActiveRecord::Migration[#{Utils.ar_version}]"
41
+ end
31
42
  end
32
43
  end
@@ -15,7 +15,7 @@ module OnlineMigrations
15
15
  end
16
16
 
17
17
  def create_migration_file
18
- migration_template("migration.rb", File.join(db_migrate_path, "install_online_migrations.rb"))
18
+ migration_template("install_migration.rb", File.join(db_migrate_path, "install_online_migrations.rb"))
19
19
  end
20
20
 
21
21
  private
@@ -0,0 +1,51 @@
1
+ class InstallOnlineMigrations < <%= migration_parent %>
2
+ def change
3
+ create_table :background_migrations do |t|
4
+ t.bigint :parent_id
5
+ t.string :migration_name, null: false
6
+ t.jsonb :arguments, default: [], null: false
7
+ t.string :batch_column_name, null: false
8
+ t.bigint :min_value, null: false
9
+ t.bigint :max_value, null: false
10
+ t.bigint :rows_count
11
+ t.integer :batch_size, null: false
12
+ t.integer :sub_batch_size, null: false
13
+ t.integer :batch_pause, null: false
14
+ t.integer :sub_batch_pause_ms, null: false
15
+ t.integer :batch_max_attempts, null: false
16
+ t.string :status, default: "enqueued", null: false
17
+ t.string :shard
18
+ t.boolean :composite, default: false, null: false
19
+ t.timestamps
20
+
21
+ t.foreign_key :background_migrations, column: :parent_id, on_delete: :cascade
22
+
23
+ t.index [:migration_name, :arguments, :shard],
24
+ unique: true, name: :index_background_migrations_on_unique_configuration
25
+ end
26
+
27
+ create_table :background_migration_jobs do |t|
28
+ t.bigint :migration_id, null: false
29
+ t.bigint :min_value, null: false
30
+ t.bigint :max_value, null: false
31
+ t.integer :batch_size, null: false
32
+ t.integer :sub_batch_size, null: false
33
+ t.integer :pause_ms, null: false
34
+ t.datetime :started_at
35
+ t.datetime :finished_at
36
+ t.string :status, default: "enqueued", null: false
37
+ t.integer :max_attempts, null: false
38
+ t.integer :attempts, default: 0, null: false
39
+ t.string :error_class
40
+ t.string :error_message
41
+ t.string :backtrace, array: true
42
+ t.timestamps
43
+
44
+ t.foreign_key :background_migrations, column: :migration_id, on_delete: :cascade
45
+
46
+ t.index [:migration_id, :max_value], name: :index_background_migration_jobs_on_max_value
47
+ t.index [:migration_id, :status, :updated_at], name: :index_background_migration_jobs_on_updated_at
48
+ t.index [:migration_id, :finished_at], name: :index_background_migration_jobs_on_finished_at
49
+ end
50
+ end
51
+ end
@@ -1,51 +1,10 @@
1
- class InstallOnlineMigrations < <%= migration_parent %>
2
- def change
3
- create_table :background_migrations do |t|
4
- t.bigint :parent_id
5
- t.string :migration_name, null: false
6
- t.jsonb :arguments, default: [], null: false
7
- t.string :batch_column_name, null: false
8
- t.bigint :min_value, null: false
9
- t.bigint :max_value, null: false
10
- t.bigint :rows_count
11
- t.integer :batch_size, null: false
12
- t.integer :sub_batch_size, null: false
13
- t.integer :batch_pause, null: false
14
- t.integer :sub_batch_pause_ms, null: false
15
- t.integer :batch_max_attempts, null: false
16
- t.string :status, default: "enqueued", null: false
17
- t.string :shard
18
- t.boolean :composite, default: false, null: false
19
- t.timestamps
20
-
21
- t.foreign_key :background_migrations, column: :parent_id, on_delete: :cascade
22
-
23
- t.index [:migration_name, :arguments, :shard],
24
- unique: true, name: :index_background_migrations_on_unique_configuration
25
- end
26
-
27
- create_table :background_migration_jobs do |t|
28
- t.bigint :migration_id, null: false
29
- t.bigint :min_value, null: false
30
- t.bigint :max_value, null: false
31
- t.integer :batch_size, null: false
32
- t.integer :sub_batch_size, null: false
33
- t.integer :pause_ms, null: false
34
- t.datetime :started_at
35
- t.datetime :finished_at
36
- t.string :status, default: "enqueued", null: false
37
- t.integer :max_attempts, null: false
38
- t.integer :attempts, default: 0, null: false
39
- t.string :error_class
40
- t.string :error_message
41
- t.string :backtrace, array: true
42
- t.timestamps
43
-
44
- t.foreign_key :background_migrations, column: :migration_id, on_delete: :cascade
1
+ class Enqueue<%= class_name %> < <%= migration_parent %>
2
+ def up
3
+ enqueue_background_migration("<%= class_name %>", ...args)
4
+ end
45
5
 
46
- t.index [:migration_id, :max_value], name: :index_background_migration_jobs_on_max_value
47
- t.index [:migration_id, :status, :updated_at], name: :index_background_migration_jobs_on_updated_at
48
- t.index [:migration_id, :finished_at], name: :index_background_migration_jobs_on_finished_at
49
- end
6
+ def down
7
+ # Make sure to pass the same arguments as in the "up" method, if any.
8
+ remove_background_migration("<%= class_name %>", ...args)
50
9
  end
51
10
  end
@@ -16,13 +16,6 @@ module OnlineMigrations
16
16
  return
17
17
  end
18
18
 
19
- if relation.joins_values.present? && !record.batch_column_name.to_s.include?(".")
20
- record.errors.add(
21
- :batch_column_name,
22
- "must be a fully-qualified column if you join a table"
23
- )
24
- end
25
-
26
19
  if relation.arel.orders.present? || relation.arel.taken.present?
27
20
  record.errors.add(
28
21
  :migration_name,
@@ -21,7 +21,7 @@ module OnlineMigrations
21
21
  end
22
22
 
23
23
  def process_batch(relation)
24
- relation.delete_all(:delete_all)
24
+ relation.delete_all
25
25
  end
26
26
  end
27
27
  end
@@ -30,7 +30,12 @@ module OnlineMigrations
30
30
 
31
31
  alias_attribute :name, :migration_name
32
32
 
33
- enum status: STATUSES.index_with(&:to_s)
33
+ # Avoid deprecation warnings.
34
+ if Utils.ar_version >= 7
35
+ enum :status, STATUSES.index_with(&:to_s)
36
+ else
37
+ enum status: STATUSES.index_with(&:to_s)
38
+ end
34
39
 
35
40
  belongs_to :parent, class_name: name, optional: true
36
41
  has_many :children, class_name: name, foreign_key: :parent_id, dependent: :delete_all
@@ -307,7 +307,7 @@ module OnlineMigrations
307
307
  # perform_action_on_relation_in_background("User", { invite_token: nil }, :generate_invite_token)
308
308
  #
309
309
  # @note This method is better suited for large tables (10/100s of millions of records).
310
- # For smaller tables it is probably better and easier to directly delete associated records.
310
+ # For smaller tables it is probably better and easier to directly perform the action on associated records.
311
311
  #
312
312
  def perform_action_on_relation_in_background(model_name, conditions, action, updates: nil, **options)
313
313
  model_name = model_name.name if model_name.is_a?(Class)
@@ -372,8 +372,7 @@ module OnlineMigrations
372
372
  def enqueue_background_migration(migration_name, *arguments, **options)
373
373
  migration = create_background_migration(migration_name, *arguments, **options)
374
374
 
375
- run_inline = OnlineMigrations.config.run_background_migrations_inline
376
- if run_inline && run_inline.call
375
+ if Utils.run_background_migrations_inline?
377
376
  runner = MigrationRunner.new(migration)
378
377
  runner.run_all_migration_jobs
379
378
  end
@@ -381,11 +380,26 @@ module OnlineMigrations
381
380
  migration
382
381
  end
383
382
 
383
+ # Removes the background migration for the given class name and arguments, if exists.
384
+ #
385
+ # @param migration_name [String, Class] Background migration job class name
386
+ # @param arguments [Array] Extra arguments the migration was originally created with
387
+ #
388
+ # @example
389
+ # remove_background_migration("BackfillProjectIssuesCount")
390
+ #
391
+ def remove_background_migration(migration_name, *arguments)
392
+ migration_name = migration_name.name if migration_name.is_a?(Class)
393
+ Migration.for_configuration(migration_name, arguments).delete_all
394
+ end
395
+
384
396
  # @private
385
397
  def create_background_migration(migration_name, *arguments, **options)
386
398
  options.assert_valid_keys(:batch_column_name, :min_value, :max_value, :batch_size, :sub_batch_size,
387
399
  :batch_pause, :sub_batch_pause_ms, :batch_max_attempts)
388
400
 
401
+ migration_name = migration_name.name if migration_name.is_a?(Class)
402
+
389
403
  migration = Migration.new(
390
404
  migration_name: migration_name,
391
405
  arguments: arguments,
@@ -37,9 +37,14 @@ module OnlineMigrations
37
37
  scope :except_succeeded, -> { where.not(status: :succeeded) }
38
38
  scope :attempts_exceeded, -> { where("attempts >= max_attempts") }
39
39
 
40
- enum status: STATUSES.index_with(&:to_s)
40
+ # Avoid deprecation warnings.
41
+ if Utils.ar_version >= 7
42
+ enum :status, STATUSES.index_with(&:to_s)
43
+ else
44
+ enum status: STATUSES.index_with(&:to_s)
45
+ end
41
46
 
42
- delegate :migration_class, :migration_object, :migration_relation, :batch_column_name,
47
+ delegate :migration_name, :migration_class, :migration_object, :migration_relation, :batch_column_name,
43
48
  :arguments, :batch_pause, to: :migration
44
49
 
45
50
  belongs_to :migration
@@ -68,7 +73,10 @@ module OnlineMigrations
68
73
  status: self.class.statuses[:enqueued],
69
74
  attempts: 0,
70
75
  started_at: nil,
71
- finished_at: nil
76
+ finished_at: nil,
77
+ error_class: nil,
78
+ error_message: nil,
79
+ backtrace: nil
72
80
  )
73
81
  end
74
82
 
@@ -46,6 +46,7 @@ module OnlineMigrations
46
46
  )
47
47
 
48
48
  ::OnlineMigrations.config.background_migrations.error_handler.call(e, migration_job)
49
+ raise if Utils.run_background_migrations_inline?
49
50
  end
50
51
 
51
52
  private
@@ -51,7 +51,11 @@ module OnlineMigrations
51
51
  # @note This method should not be used in production environments
52
52
  #
53
53
  def run_all_migration_jobs
54
- raise "This method is not intended for use in production environments" if !Utils.developer_env?
54
+ run_inline = OnlineMigrations.config.run_background_migrations_inline
55
+ if run_inline && !run_inline.call
56
+ raise "This method is not intended for use in production environments"
57
+ end
58
+
55
59
  return if migration.completed?
56
60
 
57
61
  mark_as_running
@@ -100,7 +100,7 @@ module OnlineMigrations
100
100
  end
101
101
 
102
102
  def set_statement_timeout
103
- if !@statement_timeout_set
103
+ if !defined?(@statement_timeout_set)
104
104
  if (statement_timeout = OnlineMigrations.config.statement_timeout)
105
105
  # TODO: inline this method call after deprecated `disable_statement_timeout` method removal.
106
106
  connection.__set_statement_timeout(statement_timeout)
@@ -527,6 +527,30 @@ module OnlineMigrations
527
527
  end
528
528
  alias add_belongs_to add_reference
529
529
 
530
+ def add_reference_concurrently(table_name, ref_name, **options)
531
+ # Always added by default in 5.0+
532
+ index = options.fetch(:index, true)
533
+
534
+ if index.is_a?(Hash) && index[:using].to_s == "hash" && postgresql_version < Gem::Version.new("10")
535
+ raise_error :add_hash_index
536
+ end
537
+
538
+ foreign_key = options.fetch(:foreign_key, false)
539
+
540
+ if foreign_key
541
+ foreign_table_name = Utils.foreign_table_name(ref_name, options)
542
+ @foreign_key_tables << foreign_table_name.to_s
543
+ end
544
+
545
+ if !options[:polymorphic]
546
+ type = (options[:type] || :bigint).to_sym
547
+ column_name = "#{ref_name}_id"
548
+
549
+ foreign_key_options = foreign_key.is_a?(Hash) ? foreign_key : {}
550
+ check_mismatched_foreign_key_type(table_name, column_name, type, **foreign_key_options)
551
+ end
552
+ end
553
+
530
554
  def add_index(table_name, column_name, **options)
531
555
  if options[:using].to_s == "hash" && postgresql_version < Gem::Version.new("10")
532
556
  raise_error :add_hash_index
@@ -830,8 +854,14 @@ module OnlineMigrations
830
854
  if connection.table_exists?(foreign_table_name)
831
855
  primary_key = options[:primary_key] || connection.primary_key(foreign_table_name)
832
856
  primary_key_column = column_for(foreign_table_name, primary_key)
857
+ return if primary_key_column.nil?
858
+
859
+ primary_key_type = primary_key_column.sql_type.to_sym
860
+ # Having bigint foreign keys is safe and people should
861
+ # detect integer primary keys via some other tools.
862
+ return if type == :bigint && primary_key_type == :integer
833
863
 
834
- if primary_key_column && type != primary_key_column.sql_type.to_sym
864
+ if type != primary_key_type
835
865
  raise_error :mismatched_foreign_key_type,
836
866
  table_name: table_name, column_name: column_name
837
867
  end
@@ -26,6 +26,7 @@ module OnlineMigrations
26
26
  :add_reference_concurrently,
27
27
  :change_column_type_in_background,
28
28
  :enqueue_background_migration,
29
+ :remove_background_migration,
29
30
 
30
31
  # column type change helpers
31
32
  :initialize_column_type_change,
@@ -77,6 +78,10 @@ module OnlineMigrations
77
78
 
78
79
  include StraightReversions
79
80
 
81
+ def invert_add_reference_concurrently(args)
82
+ [:remove_reference, args]
83
+ end
84
+
80
85
  def invert_swap_column_names(args)
81
86
  table_name, column1, column2 = args
82
87
  [:swap_column_names, [table_name, column2, column1]]
@@ -5,7 +5,7 @@ module OnlineMigrations
5
5
  module DatabaseTasks
6
6
  def migrate(*)
7
7
  super
8
- rescue => e # rubocop:disable Style/RescueStandardError
8
+ rescue => e
9
9
  if e.cause.is_a?(OnlineMigrations::Error)
10
10
  # strip cause
11
11
  def e.cause
@@ -110,7 +110,7 @@ A safer approach is to:
110
110
  1. ignore the column:
111
111
 
112
112
  class <%= model %> < ApplicationRecord
113
- self.ignored_columns = [\"<%= column_name %>\"]
113
+ self.ignored_columns += [\"<%= column_name %>\"]
114
114
  end
115
115
 
116
116
  2. deploy
@@ -151,7 +151,7 @@ It will use a combination of a VIEW and column aliasing to work with both column
151
151
  <% if enumerate_columns_in_select_statements %>
152
152
  5. Ignore old column
153
153
 
154
- self.ignored_columns = [:<%= column_name %>]
154
+ self.ignored_columns += [:<%= column_name %>]
155
155
 
156
156
  6. Deploy
157
157
  7. Remove the column rename config from step 1
@@ -295,10 +295,10 @@ end
295
295
  Active Record caches database columns at runtime, so if you drop a column, it can cause exceptions until your app reboots.
296
296
  A safer approach is to:
297
297
 
298
- 1. Ignore the column(s):
298
+ 1. Ignore the column:
299
299
 
300
300
  class <%= model %> < ApplicationRecord
301
- self.ignored_columns = <%= columns %>
301
+ self.ignored_columns += <%= columns %>
302
302
  end
303
303
 
304
304
  2. Deploy
@@ -310,7 +310,7 @@ A safer approach is to:
310
310
  end
311
311
  end
312
312
 
313
- 4. Remove columns ignoring
313
+ 4. Remove column ignoring from step 1
314
314
  5. Deploy
315
315
  <% end %>",
316
316
 
@@ -229,11 +229,9 @@ module OnlineMigrations
229
229
  end
230
230
 
231
231
  def lock_timeout(*)
232
- 0
233
232
  end
234
233
 
235
234
  def delay(*)
236
- 0
237
235
  end
238
236
 
239
237
  def with_lock_retries
@@ -78,7 +78,7 @@ module OnlineMigrations
78
78
  end
79
79
 
80
80
  # @private
81
- module SchemaCache7
81
+ module SchemaCache71
82
82
  # Active Record >= 7.1 changed signature of the methods,
83
83
  # see https://github.com/rails/rails/pull/48716.
84
84
  def primary_keys(connection, table_name)
@@ -154,4 +154,82 @@ module OnlineMigrations
154
154
  columns << new_column.freeze
155
155
  end
156
156
  end
157
+
158
+ # @private
159
+ module SchemaCache72
160
+ # Active Record >= 7.2 changed signature of the methods,
161
+ # see https://github.com/rails/rails/pull/48716.
162
+ def primary_keys(pool, table_name)
163
+ if (renamed_table = renamed_table?(pool, table_name))
164
+ super(pool, renamed_table)
165
+ elsif renamed_column?(pool, table_name)
166
+ super(pool, column_rename_table(table_name))
167
+ else
168
+ super
169
+ end
170
+ end
171
+
172
+ def columns(pool, table_name)
173
+ if (renamed_table = renamed_table?(pool, table_name))
174
+ super(pool, renamed_table)
175
+ elsif renamed_column?(pool, table_name)
176
+ columns = super(pool, column_rename_table(table_name))
177
+ OnlineMigrations.config.column_renames[table_name].each do |old_column_name, new_column_name|
178
+ duplicate_column(old_column_name, new_column_name, columns)
179
+ end
180
+ columns
181
+ else
182
+ super.reject { |column| column.name.end_with?("_for_type_change") }
183
+ end
184
+ end
185
+
186
+ def indexes(pool, table_name)
187
+ if (renamed_table = renamed_table?(pool, table_name))
188
+ super(pool, renamed_table)
189
+ elsif renamed_column?(pool, table_name)
190
+ super(pool, column_rename_table(table_name))
191
+ else
192
+ super
193
+ end
194
+ end
195
+
196
+ def clear_data_source_cache!(pool, name)
197
+ if (renamed_table = renamed_table?(pool, name))
198
+ super(pool, renamed_table)
199
+ end
200
+
201
+ if renamed_column?(pool, name)
202
+ super(pool, column_rename_table(name))
203
+ end
204
+
205
+ super
206
+ end
207
+
208
+ private
209
+ def renamed_table?(pool, table_name)
210
+ table_renames = OnlineMigrations.config.table_renames
211
+ if table_renames.key?(table_name)
212
+ views = pool.with_connection(&:views)
213
+ table_renames[table_name] if views.include?(table_name)
214
+ end
215
+ end
216
+
217
+ def renamed_column?(pool, table_name)
218
+ column_renames = OnlineMigrations.config.column_renames
219
+ column_renames.key?(table_name) && pool.with_connection(&:views).include?(table_name)
220
+ end
221
+
222
+ def column_rename_table(table_name)
223
+ "#{table_name}_column_rename"
224
+ end
225
+
226
+ def duplicate_column(old_column_name, new_column_name, columns)
227
+ old_column = columns.find { |column| column.name == old_column_name }
228
+ new_column = old_column.dup
229
+ # Active Record defines only reader for :name
230
+ new_column.instance_variable_set(:@name, new_column_name)
231
+ # Correspond to the Active Record freezing of each column
232
+ columns << new_column.freeze
233
+ end
234
+ end
157
235
  end
@@ -151,6 +151,11 @@ module OnlineMigrations
151
151
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: env)
152
152
  db_config.reject(&:replica?).size > 1
153
153
  end
154
+
155
+ def run_background_migrations_inline?
156
+ run_inline = OnlineMigrations.config.run_background_migrations_inline
157
+ run_inline && run_inline.call
158
+ end
154
159
  end
155
160
  end
156
161
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OnlineMigrations
4
- VERSION = "0.14.0"
4
+ VERSION = "0.15.0"
5
5
  end
@@ -7,6 +7,7 @@ require "online_migrations/utils"
7
7
  require "online_migrations/change_column_type_helpers"
8
8
  require "online_migrations/background_migrations/migration_helpers"
9
9
  require "online_migrations/schema_statements"
10
+ require "online_migrations/schema_cache"
10
11
  require "online_migrations/migration"
11
12
  require "online_migrations/migrator"
12
13
  require "online_migrations/schema_dumper"
@@ -29,11 +30,6 @@ module OnlineMigrations
29
30
  autoload :CommandChecker
30
31
  autoload :BackgroundMigration
31
32
 
32
- autoload_at "online_migrations/schema_cache" do
33
- autoload :SchemaCache
34
- autoload :SchemaCache7
35
- end
36
-
37
33
  autoload_at "online_migrations/lock_retrier" do
38
34
  autoload :LockRetrier
39
35
  autoload :ConstantLockRetrier
@@ -102,8 +98,10 @@ module OnlineMigrations
102
98
  ActiveRecord::Tasks::DatabaseTasks.singleton_class.prepend(OnlineMigrations::DatabaseTasks)
103
99
  ActiveRecord::Migration::CommandRecorder.include(OnlineMigrations::CommandRecorder)
104
100
 
105
- if OnlineMigrations::Utils.ar_version >= 7.1
106
- ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache7)
101
+ if OnlineMigrations::Utils.ar_version >= 7.2
102
+ ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache72)
103
+ elsif OnlineMigrations::Utils.ar_version >= 7.1
104
+ ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache71)
107
105
  else
108
106
  ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache)
109
107
  end
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.14.0
4
+ version: 0.15.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fatkodima
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-01 00:00:00.000000000 Z
11
+ date: 2024-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -41,6 +41,7 @@ files:
41
41
  - lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt
42
42
  - lib/generators/online_migrations/templates/background_migration.rb.tt
43
43
  - lib/generators/online_migrations/templates/initializer.rb.tt
44
+ - lib/generators/online_migrations/templates/install_migration.rb.tt
44
45
  - lib/generators/online_migrations/templates/migration.rb.tt
45
46
  - lib/generators/online_migrations/upgrade_generator.rb
46
47
  - lib/online_migrations.rb