online_migrations 0.4.1 → 0.5.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: eb5f39f15a73531072b0fe0298a119bd4e9be9ad9c1070fae8fbf21e532f6e20
4
- data.tar.gz: a9a3ff44991e42db36f4680cd2bdfc9acd0cf8c8221ff5be999ed53b2266d7ee
3
+ metadata.gz: c2515b6dd51e983fbcbdb448d33273e77d5b7f30ef53bc42dacb5127ac390fc8
4
+ data.tar.gz: b099a129bfea91da13d1dbde5c08d18fb09ae195dd83b56495c5513a881f609f
5
5
  SHA512:
6
- metadata.gz: 0fbb6f4d7455db8c41915520a25b8ae9c94cacb1041cd7111b7d4af3373000c06f647fab0e5bcf43c9fd04af7c13c82b591f7bf7f4fd82048edc07c47860100c
7
- data.tar.gz: 2a207fe4cd1ca20b3cf02866445f814e0687249928530aac33062aaf823496b9eb503c9d3bf746236a48e346ea1599518d62004ce2420199407cb381edb87d1d
6
+ metadata.gz: '0220675939d3a08c0ecb16ba3e4a212bb40106d34478b7008c2458d2eebbead2c897873634589a6ae55b0665fdf0a02fb691432c639198c7c3a59e378c10d023'
7
+ data.tar.gz: b3d9a76edb0f4e220790a7de2a2ba5f7930c9106599dd488f585f4003ae61166341feccd66cbc63965b5a181217fe5639eb17e836be48542b0070591c74b8ab6
@@ -116,9 +116,12 @@ enqueue_background_migration("MyMigrationWithArgs", arg1, arg2, ...)
116
116
 
117
117
  ## Predefined background migrations
118
118
 
119
- * `BackfillColumn` - backfills column(s) with scalar values
120
- * `CopyColumn` - copies data from one column(s) to other(s)
121
- * `ResetCounters` - resets one or more counter caches to their correct value
119
+ * `BackfillColumn` - backfills column(s) with scalar values (enqueue using `backfill_column_in_background`)
120
+ * `CopyColumn` - copies data from one column(s) to other(s) (enqueue using `copy_column_in_background`)
121
+ * `DeleteAssociatedRecords` - deletes records associated with a parent object (enqueue using `delete_associated_records_in_background`)
122
+ * `DeleteOrphanedRecords` - deletes records with one or more missing relations (enqueue using `delete_orphaned_records_in_background`)
123
+ * `PerformActionOnRelation` - performs specific action on a relation or indvidual records (enqueue using `perform_action_on_relation_in_background`)
124
+ * `ResetCounters` - resets one or more counter caches to their correct value (enqueue using `reset_counters_in_background`)
122
125
 
123
126
  ## Testing
124
127
 
@@ -262,8 +265,6 @@ The error handler should be a lambda that accepts 2 arguments:
262
265
 
263
266
  * `error`: The exception that was raised.
264
267
  * `errored_job`: An `OnlineMigrations::BackgroundMigrations::MigrationJob` object that represents a failed batch.
265
- * `errored_element`: The `OnlineMigrations::BackgroundMigrations::MigrationJob` object representing a batch,
266
- that was being processed when the Background Migration raised an exception.
267
268
 
268
269
  ### Customizing the background migrations module
269
270
 
data/CHANGELOG.md CHANGED
@@ -1,5 +1,74 @@
1
1
  ## master (unreleased)
2
2
 
3
+ ## 0.5.0 (2022-06-23)
4
+
5
+ - Added check for index corruption with PostgreSQL 14.0 to 14.3
6
+
7
+ - No need to separately remove indexes when removing a column from the small table
8
+
9
+ - Add ability to perform specific action on a relation or individual records using background migrations
10
+
11
+ Example, assuming you have lots and lots of fraud likes:
12
+
13
+ ```ruby
14
+ class DeleteFraudLikes < ActiveRecord::Migration[7.0]
15
+ def up
16
+ perform_action_on_relation_in_background("Like", { fraud: true }, :delete_all)
17
+ end
18
+ end
19
+ ```
20
+
21
+ Example, assuming you added a new column to the users and want to populate it:
22
+
23
+ ```ruby
24
+ class User < ApplicationRecord
25
+ def generate_invite_token
26
+ self.invite_token = # some complex logic
27
+ end
28
+ end
29
+
30
+ perform_action_on_relation_in_background("User", { invite_token: nil }, :generate_invite_token)
31
+ ```
32
+
33
+ You can use `delete_all`/`destroy_all`/`update_all` for the whole relation or run specific methods on individual records.
34
+
35
+ - Add ability to delete records associated with a parent object using background migrations
36
+
37
+ ```ruby
38
+ class Link < ActiveRecord::Base
39
+ has_many :clicks
40
+ end
41
+
42
+ class Click < ActiveRecord::Base
43
+ belongs_to :link
44
+ end
45
+
46
+ class DeleteSomeLinkClicks < ActiveRecord::Migration[7.0]
47
+ def up
48
+ some_link = ...
49
+ delete_associated_records_in_background("Link", some_link.id, :clicks)
50
+ end
51
+ end
52
+ ```
53
+
54
+ - Add ability to delete orphaned records using background migrations
55
+
56
+ ```ruby
57
+ class User < ApplicationRecord
58
+ has_many :posts
59
+ end
60
+
61
+ class Post < ApplicationRecord
62
+ belongs_to :author, class_name: 'User'
63
+ end
64
+
65
+ class DeleteOrphanedPosts < ActiveRecord::Migration[7.0]
66
+ def up
67
+ delete_orphaned_records_in_background("Post", :author)
68
+ end
69
+ end
70
+ ```
71
+
3
72
  ## 0.4.1 (2022-03-21)
4
73
 
5
74
  - Fix missing options in suggested command for columns removal
data/README.md CHANGED
@@ -351,7 +351,7 @@ A safer approach can be accomplished in several steps:
351
351
  ```ruby
352
352
  class CleanupChangeFilesSizeType < ActiveRecord::Migration[7.0]
353
353
  def up
354
- cleanup_change_column_type_concurrently :files, :size
354
+ cleanup_column_type_change :files, :size
355
355
  end
356
356
 
357
357
  def down
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlineMigrations
4
+ module BackgroundMigrations
5
+ # @private
6
+ class DeleteAssociatedRecords < BackgroundMigration
7
+ attr_reader :record, :association
8
+
9
+ def initialize(model_name, record_id, association, _options = {})
10
+ model = Object.const_get(model_name, false)
11
+ @record = model.find(record_id)
12
+ @association = association
13
+ end
14
+
15
+ def relation
16
+ unless @record.respond_to?(association)
17
+ raise ArgumentError, "'#{@record.class.name}' has no association called '#{association}'"
18
+ end
19
+
20
+ record.public_send(association)
21
+ end
22
+
23
+ def process_batch(relation)
24
+ relation.delete_all(:delete_all)
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlineMigrations
4
+ module BackgroundMigrations
5
+ # @private
6
+ class DeleteOrphanedRecords < BackgroundMigration
7
+ attr_reader :model, :associations
8
+
9
+ def initialize(model_name, associations, _options = {})
10
+ @model = Object.const_get(model_name, false)
11
+ @associations = associations.map(&:to_sym)
12
+ end
13
+
14
+ def relation
15
+ # For ActiveRecord 6.1+ we can use `where.missing`
16
+ # https://github.com/rails/rails/pull/34727
17
+ associations.inject(model.unscoped) do |relation, association|
18
+ reflection = model.reflect_on_association(association)
19
+ unless reflection
20
+ raise ArgumentError, "'#{model.name}' has no association called '#{association}'"
21
+ end
22
+
23
+ # left_joins was added in ActiveRecord 5.0 - https://github.com/rails/rails/pull/12071
24
+ relation
25
+ .left_joins(association)
26
+ .where(reflection.table_name => { reflection.association_primary_key => nil })
27
+ end
28
+ end
29
+
30
+ def process_batch(relation)
31
+ if Utils.ar_version > 5.0
32
+ relation.delete_all
33
+ else
34
+ # Older ActiveRecord generates incorrect query when running delete_all
35
+ primary_key = model.primary_key
36
+ model.unscoped.where(primary_key => relation.select(primary_key)).delete_all
37
+ end
38
+ end
39
+
40
+ def count
41
+ Utils.estimated_count(model.connection, model.table_name)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -21,7 +21,7 @@ module OnlineMigrations
21
21
  # @example Additional background migration options
22
22
  # backfill_column_in_background(:users, :admin, false, batch_size: 10_000)
23
23
  #
24
- # @note This method is better suited for extra large tables (100s of millions of records).
24
+ # @note This method is better suited for large tables (10/100s of millions of records).
25
25
  # For smaller tables it is probably better and easier to use more flexible `update_column_in_batches`.
26
26
  #
27
27
  # @note Consider `backfill_columns_in_background` when backfilling multiple columns
@@ -76,7 +76,7 @@ module OnlineMigrations
76
76
  # @example Additional background migration options
77
77
  # backfill_column_for_type_change_in_background(:files, :size, batch_size: 10_000)
78
78
  #
79
- # @note This method is better suited for extra large tables (100s of millions of records).
79
+ # @note This method is better suited for large tables (10/100s of millions of records).
80
80
  # For smaller tables it is probably better and easier to use more flexible `backfill_column_for_type_change`.
81
81
  #
82
82
  def backfill_column_for_type_change_in_background(table_name, column_name, model_name: nil,
@@ -131,7 +131,7 @@ module OnlineMigrations
131
131
  # @example
132
132
  # copy_column_in_background(:users, :id, :id_for_type_change)
133
133
  #
134
- # @note This method is better suited for extra large tables (100s of millions of records).
134
+ # @note This method is better suited for large tables (10/100s of millions of records).
135
135
  # For smaller tables it is probably better and easier to use more flexible `update_column_in_batches`.
136
136
  #
137
137
  def copy_column_in_background(table_name, copy_from, copy_to, model_name: nil, type_cast_function: nil, **options)
@@ -190,7 +190,7 @@ module OnlineMigrations
190
190
  #
191
191
  # @see https://api.rubyonrails.org/classes/ActiveRecord/CounterCache/ClassMethods.html#method-i-reset_counters
192
192
  #
193
- # @note This method is better suited for extra large tables (100s of millions of records).
193
+ # @note This method is better suited for large tables (10/100s of millions of records).
194
194
  # For smaller tables it is probably better and easier to use `reset_counters` from the ActiveRecord.
195
195
  #
196
196
  def reset_counters_in_background(model_name, *counters, touch: nil, **options)
@@ -205,6 +205,115 @@ module OnlineMigrations
205
205
  )
206
206
  end
207
207
 
208
+ # Deletes records with one or more missing relations using background migrations.
209
+ # This is useful when some referential integrity in the database is broken and
210
+ # you want to delete orphaned records.
211
+ #
212
+ # @param model_name [String]
213
+ # @param associations [Array]
214
+ # @param options [Hash] used to control the behavior of background migration.
215
+ # See `#enqueue_background_migration`
216
+ #
217
+ # @return [OnlineMigrations::BackgroundMigrations::Migration]
218
+ #
219
+ # @example
220
+ # delete_orphaned_records_in_background("Post", :author)
221
+ #
222
+ # @note This method is better suited for large tables (10/100s of millions of records).
223
+ # For smaller tables it is probably better and easier to directly find and delete orpahed records.
224
+ #
225
+ def delete_orphaned_records_in_background(model_name, *associations, **options)
226
+ if Utils.ar_version <= 4.2
227
+ raise "#{__method__} does not support ActiveRecord <= 4.2 yet"
228
+ end
229
+
230
+ model_name = model_name.name if model_name.is_a?(Class)
231
+
232
+ enqueue_background_migration(
233
+ "DeleteOrphanedRecords",
234
+ model_name,
235
+ associations,
236
+ **options
237
+ )
238
+ end
239
+
240
+ # Deletes associated records for a specific parent record using background migrations.
241
+ # This is useful when you are planning to remove a parent object (user, account etc)
242
+ # and needs to remove lots of its associated objects.
243
+ #
244
+ # @param model_name [String]
245
+ # @param record_id [Integer, String] parent record primary key's value
246
+ # @param association [String, Symbol] association name for which records will be removed
247
+ # @param options [Hash] used to control the behavior of background migration.
248
+ # See `#enqueue_background_migration`
249
+ #
250
+ # @return [OnlineMigrations::BackgroundMigrations::Migration]
251
+ #
252
+ # @example
253
+ # delete_associated_records_in_background("Link", 1, :clicks)
254
+ #
255
+ # @note This method is better suited for large tables (10/100s of millions of records).
256
+ # For smaller tables it is probably better and easier to directly delete associated records.
257
+ #
258
+ def delete_associated_records_in_background(model_name, record_id, association, **options)
259
+ model_name = model_name.name if model_name.is_a?(Class)
260
+
261
+ enqueue_background_migration(
262
+ "DeleteAssociatedRecords",
263
+ model_name,
264
+ record_id,
265
+ association,
266
+ **options
267
+ )
268
+ end
269
+
270
+ # Performs specific action on a relation or individual records.
271
+ # This is useful when you want to delete/destroy/update/etc records based on some conditions.
272
+ #
273
+ # @param model_name [String]
274
+ # @param conditions [Array, Hash, String] conditions to filter the relation
275
+ # @param action [String, Symbol] action to perform on the relation or individual records.
276
+ # Relation-wide available actions: `:delete_all`, `:destroy_all`, and `:update_all`.
277
+ # @param updates [Hash] updates to perform when `action` is set to `:update_all`
278
+ # @param options [Hash] used to control the behavior of background migration.
279
+ # See `#enqueue_background_migration`
280
+ #
281
+ # @return [OnlineMigrations::BackgroundMigrations::Migration]
282
+ #
283
+ # @example Delete records
284
+ # perform_action_on_relation_in_background("User", { banned: true }, :delete_all)
285
+ #
286
+ # @example Destroy records
287
+ # perform_action_on_relation_in_background("User", { banned: true }, :destroy_all)
288
+ #
289
+ # @example Update records
290
+ # perform_action_on_relation_in_background("User", { banned: nil }, :update_all, updates: { banned: false })
291
+ #
292
+ # @example Perform custom method on individual records
293
+ # class User < ApplicationRecord
294
+ # def generate_invite_token
295
+ # self.invite_token = # some complex logic
296
+ # end
297
+ # end
298
+ #
299
+ # perform_action_on_relation_in_background("User", { invite_token: nil }, :generate_invite_token)
300
+ #
301
+ # @note This method is better suited for large tables (10/100s of millions of records).
302
+ # For smaller tables it is probably better and easier to directly delete associated records.
303
+ #
304
+ def perform_action_on_relation_in_background(model_name, conditions, action, updates: nil, **options)
305
+ model_name = model_name.name if model_name.is_a?(Class)
306
+
307
+ enqueue_background_migration(
308
+ "PerformActionOnRelation",
309
+ model_name,
310
+ conditions,
311
+ action,
312
+ { updates: updates },
313
+ **options
314
+ )
315
+ end
316
+
208
317
  # Creates a background migration for the given job class name.
209
318
  #
210
319
  # A background migration runs one job at a time, computing the bounds of the next batch
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlineMigrations
4
+ module BackgroundMigrations
5
+ # @private
6
+ class PerformActionOnRelation < BackgroundMigration
7
+ attr_reader :model, :conditions, :action, :options
8
+
9
+ def initialize(model_name, conditions, action, options = {})
10
+ @model = Object.const_get(model_name, false)
11
+ @conditions = conditions
12
+ @action = action.to_sym
13
+ @options = options.symbolize_keys
14
+ end
15
+
16
+ def relation
17
+ model.unscoped.where(conditions)
18
+ end
19
+
20
+ def process_batch(relation)
21
+ case action
22
+ when :update_all
23
+ updates = options.fetch(:updates)
24
+ relation.public_send(action, updates)
25
+ when :delete_all, :destroy_all
26
+ relation.public_send(action)
27
+ else
28
+ relation.each(&action)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -173,7 +173,7 @@ module OnlineMigrations
173
173
  # backfill_column_for_type_change(:files, :size, batch_size: 10_000)
174
174
  #
175
175
  # @note This method should not be run within a transaction
176
- # @note For extra large tables (100s of millions of records)
176
+ # @note For large tables (10/100s of millions of records)
177
177
  # it is recommended to use `backfill_column_for_type_change_in_background`.
178
178
  #
179
179
  def backfill_column_for_type_change(table_name, column_name, type_cast_function: nil, **options)
@@ -316,7 +316,7 @@ module OnlineMigrations
316
316
  initialize_change_code: command_str(:initialize_column_type_change, table_name, column_name, type, **options),
317
317
  backfill_code: command_str(:backfill_column_for_type_change, table_name, column_name, **options),
318
318
  finalize_code: command_str(:finalize_column_type_change, table_name, column_name),
319
- cleanup_code: command_str(:cleanup_change_column_type_concurrently, table_name, column_name),
319
+ cleanup_code: command_str(:cleanup_column_type_change, table_name, column_name),
320
320
  cleanup_down_code: command_str(:initialize_column_type_change, table_name, column_name, existing_type)
321
321
  end
322
322
  end
@@ -383,7 +383,8 @@ module OnlineMigrations
383
383
  columns: columns.inspect,
384
384
  command: command_str(command, *args, options),
385
385
  table_name: table_name.inspect,
386
- indexes: indexes.map { |i| i.name.to_sym.inspect }
386
+ indexes: indexes.map { |i| i.name.to_sym.inspect },
387
+ small_table: small_table?(table_name)
387
388
  end
388
389
  end
389
390
 
@@ -450,6 +451,10 @@ module OnlineMigrations
450
451
  command: command_str(:add_index, table_name, column_name, **options.merge(algorithm: :concurrently))
451
452
  end
452
453
 
454
+ if options[:algorithm] == :concurrently && index_corruption?
455
+ raise_error :add_index_corruption
456
+ end
457
+
453
458
  if @removed_indexes.any?
454
459
  index = IndexDefinition.new(table: table_name, columns: column_name, **options)
455
460
  existing_indexes = connection.indexes(table_name)
@@ -576,16 +581,17 @@ module OnlineMigrations
576
581
  end
577
582
 
578
583
  def new_or_small_table?(table_name)
579
- small_tables = OnlineMigrations.config.small_tables
580
-
581
- new_table?(table_name) ||
582
- small_tables.include?(table_name.to_s)
584
+ new_table?(table_name) || small_table?(table_name)
583
585
  end
584
586
 
585
587
  def new_table?(table_name)
586
588
  @new_tables.include?(table_name.to_s)
587
589
  end
588
590
 
591
+ def small_table?(table_name)
592
+ OnlineMigrations.config.small_tables.include?(table_name.to_s)
593
+ end
594
+
589
595
  def postgresql_version
590
596
  version =
591
597
  if Utils.developer_env? && (target_version = OnlineMigrations.config.target_version)
@@ -737,6 +743,12 @@ module OnlineMigrations
737
743
  [table1.to_s, table2.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
738
744
  end
739
745
 
746
+ def index_corruption?
747
+ postgresql_version >= Gem::Version.new("14.0") &&
748
+ postgresql_version < Gem::Version.new("14.4") &&
749
+ !Utils.developer_env?
750
+ end
751
+
740
752
  def run_custom_checks(method, args)
741
753
  OnlineMigrations.config.checks.each do |options, check|
742
754
  if !options[:start_after] || version > options[:start_after]
@@ -16,7 +16,9 @@ module OnlineMigrations
16
16
  :swap_column_names,
17
17
  :add_column_with_default,
18
18
  :add_not_null_constraint,
19
+ :remove_not_null_constraint,
19
20
  :add_text_limit_constraint,
21
+ :remove_text_limit_constraint,
20
22
  :add_reference_concurrently,
21
23
  :change_column_type_in_background,
22
24
  :enqueue_background_migration,
@@ -127,11 +129,14 @@ module OnlineMigrations
127
129
  end
128
130
 
129
131
  def invert_remove_text_limit_constraint(args)
130
- unless args[2]
132
+ options = args.extract_options!
133
+ table_name, column, limit = args
134
+
135
+ unless limit
131
136
  raise ActiveRecord::IrreversibleMigration, "remove_text_limit_constraint is only reversible if given a limit."
132
137
  end
133
138
 
134
- super
139
+ [:add_text_limit_constraint, [table_name, column, limit, **options]]
135
140
  end
136
141
  end
137
142
  end
@@ -233,7 +233,7 @@ class <%= migration_name %> < <%= migration_parent %>
233
233
  end",
234
234
 
235
235
  remove_column:
236
- "<% if indexes.any? %>
236
+ "<% if !small_table && indexes.any? %>
237
237
  Removing a column will automatically remove all of the indexes that involved the removed column.
238
238
  But the indexes would be removed non-concurrently, so you need to safely remove the indexes first:
239
239
 
@@ -333,6 +333,11 @@ class <%= migration_name %> < <%= migration_parent %>
333
333
  end
334
334
  end",
335
335
 
336
+ add_index_corruption:
337
+ "Adding an index concurrently can cause silent data corruption in PostgreSQL 14.0 to 14.3.
338
+ Upgrade PostgreSQL before adding new indexes, or wrap this step in a safety_assured { ... }
339
+ block to accept the risk.",
340
+
336
341
  remove_index:
337
342
  "Removing an index non-concurrently blocks writes. Instead, use:
338
343
 
@@ -48,7 +48,7 @@ module OnlineMigrations
48
48
  # @note This method should not be run within a transaction
49
49
  # @note Consider `update_columns_in_batches` when updating multiple columns
50
50
  # to avoid rewriting the table multiple times.
51
- # @note For extra large tables (100s of millions of records)
51
+ # @note For large tables (10/100s of millions of records)
52
52
  # you may consider using `backfill_column_in_background` or `copy_column_in_background`.
53
53
  #
54
54
  def update_column_in_batches(table_name, column_name, value, **options, &block)
@@ -361,7 +361,7 @@ module OnlineMigrations
361
361
  # These steps ensure a column can be added to a large and commonly used table
362
362
  # without locking the entire table for the duration of the table modification.
363
363
  #
364
- # For extra large tables (100s of millions of records) you may consider implementing
364
+ # For large tables (10/100s of millions of records) you may consider implementing
365
365
  # the steps from this helper method yourself as a separate migrations, replacing step #3
366
366
  # with the help of background migrations (see `backfill_column_in_background`).
367
367
  #
@@ -26,7 +26,7 @@ module OnlineMigrations
26
26
 
27
27
  private
28
28
  def verbose_query_logs
29
- if Utils.ar_version > 7.0
29
+ if Utils.ar_version >= 7.0
30
30
  ActiveRecord.verbose_query_logs
31
31
  elsif Utils.ar_version >= 5.2
32
32
  ActiveRecord::Base.verbose_query_logs
@@ -34,7 +34,7 @@ module OnlineMigrations
34
34
  end
35
35
 
36
36
  def set_verbose_query_logs(value) # rubocop:disable Naming/AccessorMethodName
37
- if Utils.ar_version > 7.0
37
+ if Utils.ar_version >= 7.0
38
38
  ActiveRecord.verbose_query_logs = value
39
39
  elsif Utils.ar_version >= 5.2
40
40
  ActiveRecord::Base.verbose_query_logs = value
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OnlineMigrations
4
- VERSION = "0.4.1"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -46,6 +46,9 @@ module OnlineMigrations
46
46
  autoload :BackgroundMigrationClassValidator
47
47
  autoload :BackfillColumn
48
48
  autoload :CopyColumn
49
+ autoload :DeleteAssociatedRecords
50
+ autoload :DeleteOrphanedRecords
51
+ autoload :PerformActionOnRelation
49
52
  autoload :ResetCounters
50
53
  autoload :MigrationJob
51
54
  autoload :Migration
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.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fatkodima
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-21 00:00:00.000000000 Z
11
+ date: 2022-06-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -47,6 +47,8 @@ files:
47
47
  - lib/online_migrations/background_migrations/background_migration_class_validator.rb
48
48
  - lib/online_migrations/background_migrations/config.rb
49
49
  - lib/online_migrations/background_migrations/copy_column.rb
50
+ - lib/online_migrations/background_migrations/delete_associated_records.rb
51
+ - lib/online_migrations/background_migrations/delete_orphaned_records.rb
50
52
  - lib/online_migrations/background_migrations/migration.rb
51
53
  - lib/online_migrations/background_migrations/migration_helpers.rb
52
54
  - lib/online_migrations/background_migrations/migration_job.rb
@@ -54,6 +56,7 @@ files:
54
56
  - lib/online_migrations/background_migrations/migration_job_status_validator.rb
55
57
  - lib/online_migrations/background_migrations/migration_runner.rb
56
58
  - lib/online_migrations/background_migrations/migration_status_validator.rb
59
+ - lib/online_migrations/background_migrations/perform_action_on_relation.rb
57
60
  - lib/online_migrations/background_migrations/reset_counters.rb
58
61
  - lib/online_migrations/background_migrations/scheduler.rb
59
62
  - lib/online_migrations/batch_iterator.rb
@@ -98,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
101
  - !ruby/object:Gem::Version
99
102
  version: '0'
100
103
  requirements: []
101
- rubygems_version: 3.1.6
104
+ rubygems_version: 3.3.7
102
105
  signing_key:
103
106
  specification_version: 4
104
107
  summary: Catch unsafe PostgreSQL migrations in development and run them easier in