online_migrations 0.25.0 → 0.27.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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +31 -0
  3. data/README.md +18 -73
  4. data/docs/0.27-upgrade.md +24 -0
  5. data/docs/background_data_migrations.md +200 -101
  6. data/docs/background_schema_migrations.md +2 -2
  7. data/docs/configuring.md +8 -0
  8. data/lib/generators/online_migrations/{background_migration_generator.rb → data_migration_generator.rb} +4 -4
  9. data/lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt +1 -1
  10. data/lib/generators/online_migrations/templates/add_timestamps_to_background_migrations.rb.tt +1 -1
  11. data/lib/generators/online_migrations/templates/background_schema_migrations_change_unique_index.rb.tt +1 -1
  12. data/lib/generators/online_migrations/templates/change_background_data_migrations.rb.tt +34 -0
  13. data/lib/generators/online_migrations/templates/{background_data_migration.rb.tt → data_migration.rb.tt} +8 -9
  14. data/lib/generators/online_migrations/templates/initializer.rb.tt +22 -25
  15. data/lib/generators/online_migrations/templates/install_migration.rb.tt +9 -40
  16. data/lib/generators/online_migrations/upgrade_generator.rb +16 -8
  17. data/lib/online_migrations/active_record_batch_enumerator.rb +8 -0
  18. data/lib/online_migrations/background_data_migrations/backfill_column.rb +50 -0
  19. data/lib/online_migrations/background_data_migrations/config.rb +62 -0
  20. data/lib/online_migrations/{background_migrations → background_data_migrations}/copy_column.rb +15 -28
  21. data/lib/online_migrations/{background_migrations → background_data_migrations}/delete_associated_records.rb +9 -5
  22. data/lib/online_migrations/{background_migrations → background_data_migrations}/delete_orphaned_records.rb +5 -9
  23. data/lib/online_migrations/background_data_migrations/migration.rb +312 -0
  24. data/lib/online_migrations/{background_migrations → background_data_migrations}/migration_helpers.rb +72 -61
  25. data/lib/online_migrations/background_data_migrations/migration_job.rb +158 -0
  26. data/lib/online_migrations/background_data_migrations/migration_status_validator.rb +65 -0
  27. data/lib/online_migrations/{background_migrations → background_data_migrations}/perform_action_on_relation.rb +5 -5
  28. data/lib/online_migrations/{background_migrations → background_data_migrations}/reset_counters.rb +5 -5
  29. data/lib/online_migrations/background_data_migrations/scheduler.rb +78 -0
  30. data/lib/online_migrations/background_data_migrations/ticker.rb +62 -0
  31. data/lib/online_migrations/background_schema_migrations/config.rb +2 -2
  32. data/lib/online_migrations/background_schema_migrations/migration.rb +57 -127
  33. data/lib/online_migrations/background_schema_migrations/migration_helpers.rb +26 -47
  34. data/lib/online_migrations/background_schema_migrations/migration_runner.rb +43 -97
  35. data/lib/online_migrations/background_schema_migrations/scheduler.rb +2 -2
  36. data/lib/online_migrations/batch_iterator.rb +7 -4
  37. data/lib/online_migrations/change_column_type_helpers.rb +75 -14
  38. data/lib/online_migrations/command_checker.rb +32 -20
  39. data/lib/online_migrations/config.rb +12 -4
  40. data/lib/online_migrations/data_migration.rb +127 -0
  41. data/lib/online_migrations/error_messages.rb +16 -0
  42. data/lib/online_migrations/index_definition.rb +1 -1
  43. data/lib/online_migrations/lock_retrier.rb +5 -2
  44. data/lib/online_migrations/migration.rb +8 -1
  45. data/lib/online_migrations/schema_cache.rb +0 -78
  46. data/lib/online_migrations/schema_statements.rb +18 -74
  47. data/lib/online_migrations/shard_aware.rb +44 -0
  48. data/lib/online_migrations/utils.rb +1 -20
  49. data/lib/online_migrations/verbose_sql_logs.rb +1 -7
  50. data/lib/online_migrations/version.rb +1 -1
  51. data/lib/online_migrations.rb +19 -19
  52. metadata +25 -24
  53. data/lib/online_migrations/background_migration.rb +0 -64
  54. data/lib/online_migrations/background_migrations/backfill_column.rb +0 -54
  55. data/lib/online_migrations/background_migrations/background_migration_class_validator.rb +0 -29
  56. data/lib/online_migrations/background_migrations/config.rb +0 -74
  57. data/lib/online_migrations/background_migrations/migration.rb +0 -329
  58. data/lib/online_migrations/background_migrations/migration_job.rb +0 -109
  59. data/lib/online_migrations/background_migrations/migration_job_runner.rb +0 -66
  60. data/lib/online_migrations/background_migrations/migration_job_status_validator.rb +0 -29
  61. data/lib/online_migrations/background_migrations/migration_runner.rb +0 -161
  62. data/lib/online_migrations/background_migrations/migration_status_validator.rb +0 -48
  63. data/lib/online_migrations/background_migrations/scheduler.rb +0 -42
@@ -3,7 +3,7 @@
3
3
  module OnlineMigrations
4
4
  module SchemaStatements
5
5
  include ChangeColumnTypeHelpers
6
- include BackgroundMigrations::MigrationHelpers
6
+ include BackgroundDataMigrations::MigrationHelpers
7
7
  include BackgroundSchemaMigrations::MigrationHelpers
8
8
 
9
9
  # Updates the value of a column in batches.
@@ -568,8 +568,8 @@ module OnlineMigrations
568
568
  #
569
569
  def add_text_limit_constraint(table_name, column_name, limit, name: nil, validate: true)
570
570
  column = column_for(table_name, column_name)
571
- if column.type != :text
572
- raise "add_text_limit_constraint must be used only with :text columns"
571
+ if column.type != :text && column.type != :string
572
+ raise "add_text_limit_constraint must be used only with :text or :string columns"
573
573
  end
574
574
 
575
575
  name ||= __text_limit_constraint_name(table_name, column_name)
@@ -710,16 +710,12 @@ module OnlineMigrations
710
710
  index_name = (options[:name] || index_name(table_name, column_name)).to_s
711
711
  indexes(table_name).find { |i| i.name == index_name }
712
712
  else
713
- # Rewrite this with `IndexDefinition#defined_for?` when Active Record >= 7.1 is supported.
714
- # See https://github.com/rails/rails/pull/45160.
715
- indexes(table_name).find { |i| __index_defined_for?(i, column_name, **options) }
713
+ indexes(table_name).find { |i| i.defined_for?(column_name, **options) }
716
714
  end
717
715
 
718
716
  if index
719
- schema = __schema_for_table(table_name)
720
-
721
- if __index_valid?(index.name, schema: schema)
722
- Utils.say("Index was not created because it already exists.")
717
+ if index.valid?
718
+ Utils.say("Index #{index.name} was not created because it already exists.")
723
719
  return
724
720
  else
725
721
  Utils.say("Recreating invalid index: table_name: #{table_name}, column_name: #{column_name}")
@@ -764,22 +760,6 @@ module OnlineMigrations
764
760
  end
765
761
  end
766
762
 
767
- # @private
768
- # From ActiveRecord. Will not be needed for ActiveRecord >= 7.1.
769
- def index_name(table_name, options)
770
- if options.is_a?(Hash)
771
- if options[:column]
772
- Utils.index_name(table_name, options[:column])
773
- elsif options[:name]
774
- options[:name]
775
- else
776
- raise ArgumentError, "You must specify the index name"
777
- end
778
- else
779
- index_name(table_name, column: options)
780
- end
781
- end
782
-
783
763
  # Extends default method to be idempotent.
784
764
  #
785
765
  # @see https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_foreign_key
@@ -833,7 +813,7 @@ module OnlineMigrations
833
813
  # @see https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_check_constraint
834
814
  #
835
815
  def add_check_constraint(table_name, expression, **options)
836
- if __check_constraint_exists?(table_name, expression: expression, **options)
816
+ if check_constraint_exists?(table_name, expression: expression, **options)
837
817
  Utils.say(<<~MSG.squish)
838
818
  Check constraint was not created because it already exists (this may be due to an aborted migration or similar).
839
819
  table_name: #{table_name}, expression: #{expression}
@@ -864,7 +844,7 @@ module OnlineMigrations
864
844
  # @see https://edgeapi.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-remove_check_constraint
865
845
  #
866
846
  def remove_check_constraint(table_name, expression = nil, **options)
867
- if __check_constraint_exists?(table_name, expression: expression, **options)
847
+ if check_constraint_exists?(table_name, expression: expression, **options)
868
848
  super
869
849
  else
870
850
  Utils.say(<<~MSG.squish)
@@ -874,16 +854,14 @@ module OnlineMigrations
874
854
  end
875
855
  end
876
856
 
877
- if Utils.ar_version >= 7.1
878
- def add_exclusion_constraint(table_name, expression, **options)
879
- if __exclusion_constraint_exists?(table_name, expression: expression, **options)
880
- Utils.say(<<~MSG.squish)
881
- Exclusion constraint was not created because it already exists (this may be due to an aborted migration or similar).
882
- table_name: #{table_name}, expression: #{expression}
883
- MSG
884
- else
885
- super
886
- end
857
+ def add_exclusion_constraint(table_name, expression, **options)
858
+ if __exclusion_constraint_exists?(table_name, expression: expression, **options)
859
+ Utils.say(<<~MSG.squish)
860
+ Exclusion constraint was not created because it already exists (this may be due to an aborted migration or similar).
861
+ table_name: #{table_name}, expression: #{expression}
862
+ MSG
863
+ else
864
+ super
887
865
  end
888
866
  end
889
867
 
@@ -932,20 +910,9 @@ module OnlineMigrations
932
910
  end
933
911
  end
934
912
 
935
- # Will not be needed for Active Record >= 7.1
936
- def __index_defined_for?(index, columns = nil, name: nil, unique: nil, valid: nil, include: nil, nulls_not_distinct: nil, **options)
937
- columns = options[:column] if columns.blank?
938
- (columns.nil? || Array(index.columns) == Array(columns).map(&:to_s)) &&
939
- (name.nil? || index.name == name.to_s) &&
940
- (unique.nil? || index.unique == unique) &&
941
- (valid.nil? || index.valid == valid) &&
942
- (include.nil? || Array(index.include) == Array(include).map(&:to_s)) &&
943
- (nulls_not_distinct.nil? || index.nulls_not_distinct == nulls_not_distinct)
944
- end
945
-
946
913
  def __not_null_constraint_exists?(table_name, column_name, name: nil)
947
914
  name ||= __not_null_constraint_name(table_name, column_name)
948
- __check_constraint_exists?(table_name, name: name)
915
+ check_constraint_exists?(table_name, name: name)
949
916
  end
950
917
 
951
918
  def __not_null_constraint_name(table_name, column_name)
@@ -958,21 +925,7 @@ module OnlineMigrations
958
925
 
959
926
  def __text_limit_constraint_exists?(table_name, column_name, name: nil)
960
927
  name ||= __text_limit_constraint_name(table_name, column_name)
961
- __check_constraint_exists?(table_name, name: name)
962
- end
963
-
964
- # Can use index validity attribute for Active Record >= 7.1.
965
- def __index_valid?(index_name, schema:)
966
- select_value(<<~SQL)
967
- SELECT indisvalid
968
- FROM pg_index i
969
- JOIN pg_class c
970
- ON i.indexrelid = c.oid
971
- JOIN pg_namespace n
972
- ON c.relnamespace = n.oid
973
- WHERE n.nspname = #{schema}
974
- AND c.relname = #{quote(index_name)}
975
- SQL
928
+ check_constraint_exists?(table_name, name: name)
976
929
  end
977
930
 
978
931
  def __copy_foreign_key(fk, to_column, **options)
@@ -996,15 +949,6 @@ module OnlineMigrations
996
949
  end
997
950
  end
998
951
 
999
- # Can be replaced by native method in Active Record >= 7.1.
1000
- def __check_constraint_exists?(table_name, **options)
1001
- if !options.key?(:name) && !options.key?(:expression)
1002
- raise ArgumentError, "At least one of :name or :expression must be supplied"
1003
- end
1004
-
1005
- check_constraint_for(table_name, **options).present?
1006
- end
1007
-
1008
952
  def __exclusion_constraint_exists?(table_name, **options)
1009
953
  if !options.key?(:name) && !options.key?(:expression)
1010
954
  raise ArgumentError, "At least one of :name or :expression must be supplied"
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module OnlineMigrations
4
+ module ShardAware
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ before_validation :set_connection_class_name
9
+ end
10
+
11
+ def on_shard_if_present(&block)
12
+ if shard
13
+ connection_class.connected_to(shard: shard.to_sym, role: :writing, &block)
14
+ else
15
+ yield
16
+ end
17
+ end
18
+
19
+ def connection_class_name=(value)
20
+ if value && (klass = value.safe_constantize)
21
+ if !(klass <= ActiveRecord::Base)
22
+ raise ArgumentError, "connection_class_name is not an ActiveRecord::Base child class"
23
+ end
24
+
25
+ connection_class = Utils.find_connection_class(klass)
26
+ super(connection_class.name)
27
+ end
28
+ end
29
+
30
+ # @private
31
+ def connection_class
32
+ if connection_class_name && (klass = connection_class_name.safe_constantize)
33
+ Utils.find_connection_class(klass)
34
+ else
35
+ ActiveRecord::Base
36
+ end
37
+ end
38
+
39
+ private
40
+ def set_connection_class_name
41
+ self.connection_class_name ||= "ActiveRecord::Base"
42
+ end
43
+ end
44
+ end
@@ -69,23 +69,6 @@ module OnlineMigrations
69
69
  end
70
70
  end
71
71
 
72
- # Implementation is from ActiveRecord.
73
- # This is not needed for ActiveRecord >= 7.1 (https://github.com/rails/rails/pull/47753).
74
- def index_name(table_name, column_name)
75
- max_index_name_size = 62
76
- name = "index_#{table_name}_on_#{Array(column_name) * '_and_'}"
77
- return name if name.bytesize <= max_index_name_size
78
-
79
- # Fallback to short version, add hash to ensure uniqueness
80
- hashed_identifier = "_#{OpenSSL::Digest::SHA256.hexdigest(name).first(10)}"
81
- name = "idx_on_#{Array(column_name) * '_'}"
82
-
83
- short_limit = max_index_name_size - hashed_identifier.bytesize
84
- short_name = name[0, short_limit]
85
-
86
- "#{short_name}#{hashed_identifier}"
87
- end
88
-
89
72
  # Returns estimated rows count for a table.
90
73
  # https://www.citusdata.com/blog/2016/10/12/count-performance/
91
74
  def estimated_count(connection, table_name)
@@ -144,9 +127,7 @@ module OnlineMigrations
144
127
  # This is the way that currently is used in ActiveRecord tests themselves.
145
128
  pool_manager = ActiveRecord::Base.connection_handler.send(:get_pool_manager, ancestor.name)
146
129
 
147
- # .uniq call is not needed for Active Record 7.1+
148
- # See https://github.com/rails/rails/pull/49284.
149
- return pool_manager.shard_names.uniq if pool_manager
130
+ return pool_manager.shard_names if pool_manager
150
131
  end
151
132
  end
152
133
 
@@ -14,13 +14,7 @@ module OnlineMigrations
14
14
  stdout_logger.level = @activerecord_logger_was.level
15
15
  stdout_logger = ActiveSupport::TaggedLogging.new(stdout_logger)
16
16
 
17
- combined_logger =
18
- # Broadcasting logs API was changed in https://github.com/rails/rails/pull/48615.
19
- if Utils.ar_version >= 7.1
20
- ActiveSupport::BroadcastLogger.new(stdout_logger, @activerecord_logger_was)
21
- else
22
- stdout_logger.extend(ActiveSupport::Logger.broadcast(@activerecord_logger_was))
23
- end
17
+ combined_logger = ActiveSupport::BroadcastLogger.new(stdout_logger, @activerecord_logger_was)
24
18
 
25
19
  ActiveRecord::Base.logger = combined_logger
26
20
  ActiveRecord.verbose_query_logs = false
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OnlineMigrations
4
- VERSION = "0.25.0"
4
+ VERSION = "0.27.0"
5
5
  end
@@ -6,7 +6,8 @@ require "online_migrations/version"
6
6
  require "online_migrations/utils"
7
7
  require "online_migrations/background_schema_migrations/migration_helpers"
8
8
  require "online_migrations/change_column_type_helpers"
9
- require "online_migrations/background_migrations/migration_helpers"
9
+ require "online_migrations/background_data_migrations/migration_helpers"
10
+ require "online_migrations/active_record_batch_enumerator"
10
11
  require "online_migrations/schema_statements"
11
12
  require "online_migrations/schema_cache"
12
13
  require "online_migrations/migration"
@@ -29,7 +30,8 @@ module OnlineMigrations
29
30
  autoload :ForeignKeysCollector
30
31
  autoload :IndexDefinition
31
32
  autoload :CommandChecker
32
- autoload :BackgroundMigration
33
+ autoload :DataMigration
34
+ autoload :ShardAware
33
35
 
34
36
  autoload_at "online_migrations/lock_retrier" do
35
37
  autoload :LockRetrier
@@ -40,24 +42,21 @@ module OnlineMigrations
40
42
 
41
43
  autoload :CopyTrigger
42
44
 
43
- module BackgroundMigrations
45
+ module BackgroundDataMigrations
44
46
  extend ActiveSupport::Autoload
45
47
 
46
48
  autoload :Config
47
49
  autoload :MigrationStatusValidator
48
- autoload :MigrationJobStatusValidator
49
- autoload :BackgroundMigrationClassValidator
50
50
  autoload :BackfillColumn
51
51
  autoload :CopyColumn
52
52
  autoload :DeleteAssociatedRecords
53
53
  autoload :DeleteOrphanedRecords
54
54
  autoload :PerformActionOnRelation
55
55
  autoload :ResetCounters
56
- autoload :MigrationJob
57
56
  autoload :Migration
58
- autoload :MigrationJobRunner
59
- autoload :MigrationRunner
57
+ autoload :MigrationJob
60
58
  autoload :Scheduler
59
+ autoload :Ticker
61
60
  end
62
61
 
63
62
  module BackgroundSchemaMigrations
@@ -70,6 +69,10 @@ module OnlineMigrations
70
69
  autoload :Scheduler
71
70
  end
72
71
 
72
+ # Make aliases for less typing.
73
+ DataMigrations = BackgroundDataMigrations
74
+ SchemaMigrations = BackgroundSchemaMigrations
75
+
73
76
  class << self
74
77
  # @private
75
78
  attr_accessor :current_migration
@@ -87,10 +90,10 @@ module OnlineMigrations
87
90
  # @option options [String, Symbol, nil] :shard The name of the shard to run
88
91
  # background data migrations on. By default runs on all shards.
89
92
  #
90
- def run_background_migrations(**options)
91
- BackgroundMigrations::Scheduler.run(**options)
93
+ def run_background_data_migrations(**options)
94
+ BackgroundDataMigrations::Scheduler.run(**options)
92
95
  end
93
- alias run_background_data_migrations run_background_migrations
96
+ alias run_background_migrations run_background_data_migrations
94
97
 
95
98
  # Run background schema migrations
96
99
  #
@@ -102,12 +105,7 @@ module OnlineMigrations
102
105
  end
103
106
 
104
107
  def deprecator
105
- @deprecator ||=
106
- if Utils.ar_version >= 7.1
107
- ActiveSupport::Deprecation.new(nil, "online_migrations")
108
- else
109
- ActiveSupport::Deprecation
110
- end
108
+ @deprecator ||= ActiveSupport::Deprecation.new(nil, "online_migrations")
111
109
  end
112
110
 
113
111
  # @private
@@ -124,11 +122,13 @@ module OnlineMigrations
124
122
 
125
123
  if OnlineMigrations::Utils.ar_version >= 7.2
126
124
  ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache72)
127
- elsif OnlineMigrations::Utils.ar_version >= 7.1
128
- ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache71)
129
125
  else
130
126
  ActiveRecord::ConnectionAdapters::SchemaCache.prepend(OnlineMigrations::SchemaCache)
131
127
  end
128
+
129
+ if !ActiveRecord::Batches::BatchEnumerator.method_defined?(:use_ranges)
130
+ ActiveRecord::Batches::BatchEnumerator.include(OnlineMigrations::ActiveRecordBatchEnumerator)
131
+ end
132
132
  end
133
133
  end
134
134
  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.25.0
4
+ version: 0.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - fatkodima
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-02-03 00:00:00.000000000 Z
11
+ date: 2025-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '7.0'
19
+ version: '7.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '7.0'
26
+ version: '7.1'
27
27
  description:
28
28
  email:
29
29
  - fatkodima123@gmail.com
@@ -34,39 +34,38 @@ files:
34
34
  - CHANGELOG.md
35
35
  - LICENSE.txt
36
36
  - README.md
37
+ - docs/0.27-upgrade.md
37
38
  - docs/background_data_migrations.md
38
39
  - docs/background_schema_migrations.md
39
40
  - docs/configuring.md
40
- - lib/generators/online_migrations/background_migration_generator.rb
41
+ - lib/generators/online_migrations/data_migration_generator.rb
41
42
  - lib/generators/online_migrations/install_generator.rb
42
43
  - lib/generators/online_migrations/templates/add_sharding_to_online_migrations.rb.tt
43
44
  - lib/generators/online_migrations/templates/add_timestamps_to_background_migrations.rb.tt
44
- - lib/generators/online_migrations/templates/background_data_migration.rb.tt
45
45
  - lib/generators/online_migrations/templates/background_schema_migrations_change_unique_index.rb.tt
46
+ - lib/generators/online_migrations/templates/change_background_data_migrations.rb.tt
46
47
  - lib/generators/online_migrations/templates/create_background_schema_migrations.rb.tt
48
+ - lib/generators/online_migrations/templates/data_migration.rb.tt
47
49
  - lib/generators/online_migrations/templates/initializer.rb.tt
48
50
  - lib/generators/online_migrations/templates/install_migration.rb.tt
49
51
  - lib/generators/online_migrations/templates/migration.rb.tt
50
52
  - lib/generators/online_migrations/upgrade_generator.rb
51
53
  - lib/online_migrations.rb
54
+ - lib/online_migrations/active_record_batch_enumerator.rb
52
55
  - lib/online_migrations/application_record.rb
53
- - lib/online_migrations/background_migration.rb
54
- - lib/online_migrations/background_migrations/backfill_column.rb
55
- - lib/online_migrations/background_migrations/background_migration_class_validator.rb
56
- - lib/online_migrations/background_migrations/config.rb
57
- - lib/online_migrations/background_migrations/copy_column.rb
58
- - lib/online_migrations/background_migrations/delete_associated_records.rb
59
- - lib/online_migrations/background_migrations/delete_orphaned_records.rb
60
- - lib/online_migrations/background_migrations/migration.rb
61
- - lib/online_migrations/background_migrations/migration_helpers.rb
62
- - lib/online_migrations/background_migrations/migration_job.rb
63
- - lib/online_migrations/background_migrations/migration_job_runner.rb
64
- - lib/online_migrations/background_migrations/migration_job_status_validator.rb
65
- - lib/online_migrations/background_migrations/migration_runner.rb
66
- - lib/online_migrations/background_migrations/migration_status_validator.rb
67
- - lib/online_migrations/background_migrations/perform_action_on_relation.rb
68
- - lib/online_migrations/background_migrations/reset_counters.rb
69
- - lib/online_migrations/background_migrations/scheduler.rb
56
+ - lib/online_migrations/background_data_migrations/backfill_column.rb
57
+ - lib/online_migrations/background_data_migrations/config.rb
58
+ - lib/online_migrations/background_data_migrations/copy_column.rb
59
+ - lib/online_migrations/background_data_migrations/delete_associated_records.rb
60
+ - lib/online_migrations/background_data_migrations/delete_orphaned_records.rb
61
+ - lib/online_migrations/background_data_migrations/migration.rb
62
+ - lib/online_migrations/background_data_migrations/migration_helpers.rb
63
+ - lib/online_migrations/background_data_migrations/migration_job.rb
64
+ - lib/online_migrations/background_data_migrations/migration_status_validator.rb
65
+ - lib/online_migrations/background_data_migrations/perform_action_on_relation.rb
66
+ - lib/online_migrations/background_data_migrations/reset_counters.rb
67
+ - lib/online_migrations/background_data_migrations/scheduler.rb
68
+ - lib/online_migrations/background_data_migrations/ticker.rb
70
69
  - lib/online_migrations/background_schema_migrations/config.rb
71
70
  - lib/online_migrations/background_schema_migrations/migration.rb
72
71
  - lib/online_migrations/background_schema_migrations/migration_helpers.rb
@@ -79,6 +78,7 @@ files:
79
78
  - lib/online_migrations/command_recorder.rb
80
79
  - lib/online_migrations/config.rb
81
80
  - lib/online_migrations/copy_trigger.rb
81
+ - lib/online_migrations/data_migration.rb
82
82
  - lib/online_migrations/database_tasks.rb
83
83
  - lib/online_migrations/error_messages.rb
84
84
  - lib/online_migrations/foreign_keys_collector.rb
@@ -89,6 +89,7 @@ files:
89
89
  - lib/online_migrations/schema_cache.rb
90
90
  - lib/online_migrations/schema_dumper.rb
91
91
  - lib/online_migrations/schema_statements.rb
92
+ - lib/online_migrations/shard_aware.rb
92
93
  - lib/online_migrations/utils.rb
93
94
  - lib/online_migrations/verbose_sql_logs.rb
94
95
  - lib/online_migrations/version.rb
@@ -107,7 +108,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
108
  requirements:
108
109
  - - ">="
109
110
  - !ruby/object:Gem::Version
110
- version: '3.0'
111
+ version: '3.1'
111
112
  required_rubygems_version: !ruby/object:Gem::Requirement
112
113
  requirements:
113
114
  - - ">="
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OnlineMigrations
4
- # Base class that is inherited by the host application's background migration classes.
5
- class BackgroundMigration
6
- class NotFoundError < NameError; end
7
-
8
- class << self
9
- # Finds a Background Migration with the given name.
10
- #
11
- # @param name [String] the name of the Background Migration to be found.
12
- #
13
- # @return [BackgroundMigration] the Background Migration with the given name.
14
- #
15
- # @raise [NotFoundError] if a Background Migration with the given name does not exist.
16
- #
17
- def named(name)
18
- namespace = OnlineMigrations.config.background_migrations.migrations_module.constantize
19
- internal_namespace = ::OnlineMigrations::BackgroundMigrations
20
-
21
- migration = "#{namespace}::#{name}".safe_constantize ||
22
- "#{internal_namespace}::#{name}".safe_constantize
23
-
24
- raise NotFoundError.new("Background Migration #{name} not found", name) if migration.nil?
25
- if !(migration.is_a?(Class) && migration < self)
26
- raise NotFoundError.new("#{name} is not a Background Migration", name)
27
- end
28
-
29
- migration
30
- end
31
- end
32
-
33
- # The relation to be iterated over.
34
- #
35
- # @return [ActiveRecord::Relation]
36
- #
37
- # @raise [NotImplementedError] with a message advising subclasses to
38
- # implement an override for this method.
39
- #
40
- def relation
41
- raise NotImplementedError, "#{self.class.name} must implement a 'relation' method"
42
- end
43
-
44
- # Processes one batch.
45
- #
46
- # @param _relation [ActiveRecord::Relation] the current batch from the enumerator being iterated
47
- # @return [void]
48
- #
49
- # @raise [NotImplementedError] with a message advising subclasses to
50
- # implement an override for this method.
51
- #
52
- def process_batch(_relation)
53
- raise NotImplementedError, "#{self.class.name} must implement a 'process_batch' method"
54
- end
55
-
56
- # Returns the count of rows that will be iterated over (optional, to be able to show progress).
57
- #
58
- # @return [Integer, nil, :no_count]
59
- #
60
- def count
61
- :no_count
62
- end
63
- end
64
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OnlineMigrations
4
- module BackgroundMigrations
5
- # @private
6
- class BackfillColumn < BackgroundMigration
7
- attr_reader :table_name, :updates, :model_name
8
-
9
- def initialize(table_name, updates, model_name = nil)
10
- @table_name = table_name
11
- @updates = updates
12
- @model_name = model_name
13
- end
14
-
15
- def relation
16
- column, value = updates.first
17
-
18
- if updates.size == 1 && !value.nil?
19
- # If value is nil, the generated SQL is correct (`WHERE column IS NOT NULL`).
20
- # Otherwise, the SQL is `WHERE column != value`. This condition ignores column
21
- # with NULLs in it, so we need to also manually check for NULLs.
22
- quoted_column = connection.quote_column_name(column)
23
- model.unscoped.where("#{quoted_column} != ? OR #{quoted_column} IS NULL", value)
24
- else
25
- model.unscoped.where.not(updates)
26
- end
27
- end
28
-
29
- def process_batch(relation)
30
- relation.update_all(updates)
31
- end
32
-
33
- def count
34
- # Exact counts are expensive on large tables, since PostgreSQL
35
- # needs to do a full scan. An estimated count should give a pretty decent
36
- # approximation of rows count in this case.
37
- Utils.estimated_count(connection, table_name)
38
- end
39
-
40
- private
41
- def model
42
- @model ||= if model_name.present?
43
- Object.const_get(model_name, false)
44
- else
45
- Utils.define_model(table_name)
46
- end
47
- end
48
-
49
- def connection
50
- model.connection
51
- end
52
- end
53
- end
54
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OnlineMigrations
4
- module BackgroundMigrations
5
- # @private
6
- class BackgroundMigrationClassValidator < ActiveModel::Validator
7
- def validate(record)
8
- relation = record.migration_relation
9
- migration_name = record.migration_name
10
-
11
- if !relation.is_a?(ActiveRecord::Relation)
12
- record.errors.add(
13
- :migration_name,
14
- "#{migration_name}#relation must return an ActiveRecord::Relation object"
15
- )
16
- return
17
- end
18
-
19
- if relation.arel.orders.present? || relation.arel.taken.present?
20
- record.errors.add(
21
- :migration_name,
22
- "#{migration_name}#relation cannot use ORDER BY or LIMIT due to the way how iteration with a cursor is designed. " \
23
- "You can use other ways to limit the number of rows, e.g. a WHERE condition on the primary key column."
24
- )
25
- end
26
- end
27
- end
28
- end
29
- end