online_migrations 0.5.0 → 0.5.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2515b6dd51e983fbcbdb448d33273e77d5b7f30ef53bc42dacb5127ac390fc8
4
- data.tar.gz: b099a129bfea91da13d1dbde5c08d18fb09ae195dd83b56495c5513a881f609f
3
+ metadata.gz: 5f0ae9026f83b836b520090730426b5cf93fe18e193f21ea28cd11b96ebb78a8
4
+ data.tar.gz: 939595b3b732d6351fbab4403f0271e47a2c42b770a9732e30cdc0f52479ce7b
5
5
  SHA512:
6
- metadata.gz: '0220675939d3a08c0ecb16ba3e4a212bb40106d34478b7008c2458d2eebbead2c897873634589a6ae55b0665fdf0a02fb691432c639198c7c3a59e378c10d023'
7
- data.tar.gz: b3d9a76edb0f4e220790a7de2a2ba5f7930c9106599dd488f585f4003ae61166341feccd66cbc63965b5a181217fe5639eb17e836be48542b0070591c74b8ab6
6
+ metadata.gz: d09f3b4a3592cada77cf27e152669d6c94e5bd15e3c2930aa18c6ca6de6cd3c0e588314e95cd7cb058e43fea22343c8529ed7c2a11ec60d247ce6479bce58374
7
+ data.tar.gz: 42185f369b8adb87c10c2e0cfb29891784d3b55bd0c41cc3b92804fb0d8f71d9b70f4349b26a5752ff1f6b9d8ebbdbc061667157d6b1023190907104f71e93b1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,39 @@
1
1
  ## master (unreleased)
2
2
 
3
+ ## 0.5.2 (2022-10-04)
4
+
5
+ - Fix sequence resetting in tests that use fixtures
6
+
7
+ - Fix `update_column_in_batches` for SQL subquery values
8
+
9
+ It generated inefficient queries before, e.g.:
10
+
11
+ ```ruby
12
+ update_column_in_batches(:users, :comments_count, Arel.sql(<<~SQL))
13
+ (select count(*) from comments where comments.user_id = users.id)
14
+ SQL
15
+ ```
16
+
17
+ Generated SQL queries before:
18
+ ```sql
19
+ update users
20
+ set comments_count = (..count subquery..)
21
+ where comments_count is null or comments_count != (..count subquery..)
22
+ ```
23
+
24
+ Generated SQL queries now:
25
+ ```sql
26
+ update users set comments_count = (..count subquery..)
27
+ ```
28
+
29
+ - Fix check for `add_column` with `default: nil` for PostgreSQL < 11
30
+ - Replacing a unique index when other unique index with the prefix of columns exists is safe
31
+
32
+ ## 0.5.1 (2022-07-19)
33
+
34
+ - Raise for possible index corruption in all environments (previously, the check was made only
35
+ in the production environment)
36
+
3
37
  ## 0.5.0 (2022-06-23)
4
38
 
5
39
  - Added check for index corruption with PostgreSQL 14.0 to 14.3
@@ -10,21 +10,21 @@ module OnlineMigrations
10
10
 
11
11
  source_root File.expand_path("templates", __dir__)
12
12
 
13
- def create_migration_file
14
- migration_template("migration.rb", File.join(migrations_dir, "install_online_migrations.rb"))
15
- end
16
-
17
13
  def copy_initializer_file
18
14
  template("initializer.rb", "config/initializers/online_migrations.rb")
19
15
  end
20
16
 
17
+ def create_migration_file
18
+ migration_template("migration.rb", File.join(migrations_dir, "install_online_migrations.rb"))
19
+ end
20
+
21
21
  private
22
22
  def migration_parent
23
23
  Utils.migration_parent_string
24
24
  end
25
25
 
26
26
  def start_after
27
- self.class.next_migration_number(migrations_dir)
27
+ self.class.current_migration_number(migrations_dir)
28
28
  end
29
29
 
30
30
  def migrations_dir
@@ -59,11 +59,11 @@ OnlineMigrations.configure do |config|
59
59
 
60
60
  # Add custom checks. Use the `stop!` method to stop migrations.
61
61
  #
62
- # config.add_check do |method, args|
63
- # if method == :add_column && args[0].to_s == "users"
64
- # stop!("No more columns on the users table")
65
- # end
62
+ # config.add_check do |method, args|
63
+ # if method == :add_column && args[0].to_s == "users"
64
+ # stop!("No more columns on the users table")
66
65
  # end
66
+ # end
67
67
 
68
68
  # ==> Background migrations configuration
69
69
  # The number of rows to process in a single background migration run.
@@ -100,7 +100,7 @@ module OnlineMigrations
100
100
  end.to_h
101
101
 
102
102
  if (extra_keys = (options.keys - conversions.keys)).any?
103
- raise ArgumentError, "Options has unknown keys: #{extra_keys.map(&:inspect).join(', ')}. "\
103
+ raise ArgumentError, "Options has unknown keys: #{extra_keys.map(&:inspect).join(', ')}. " \
104
104
  "Can contain only column names: #{conversions.keys.map(&:inspect).join(', ')}."
105
105
  end
106
106
 
@@ -400,7 +400,7 @@ module OnlineMigrations
400
400
 
401
401
  # This is necessary as we can't properly rename indexes such as "taggings_idx".
402
402
  unless index.name.include?(from_column)
403
- raise "The index #{index.name} can not be copied as it does not "\
403
+ raise "The index #{index.name} can not be copied as it does not " \
404
404
  "mention the old column. You have to rename this index manually first."
405
405
  end
406
406
 
@@ -174,8 +174,8 @@ module OnlineMigrations
174
174
  def add_column(table_name, column_name, type, **options)
175
175
  default = options[:default]
176
176
  volatile_default = false
177
- if !new_or_small_table?(table_name) && !default.nil? &&
178
- (postgresql_version < Gem::Version.new("11") || (volatile_default = Utils.volatile_default?(connection, type, default)))
177
+ if !new_or_small_table?(table_name) && options.key?(:default) &&
178
+ (postgresql_version < Gem::Version.new("11") || (!default.nil? && (volatile_default = Utils.volatile_default?(connection, type, default))))
179
179
 
180
180
  raise_error :add_column_with_default,
181
181
  code: command_str(:add_column_with_default, table_name, column_name, type, options),
@@ -478,9 +478,17 @@ module OnlineMigrations
478
478
  command: command_str(:remove_index, table_name, **options.merge(algorithm: :concurrently))
479
479
  end
480
480
 
481
- if options[:column] || options[:name]
482
- options[:column] ||= connection.indexes(table_name).find { |index| index.name == options[:name].to_s }
483
- @removed_indexes << IndexDefinition.new(table: table_name, columns: options.delete(:column), **options)
481
+ index_def = connection.indexes(table_name).find do |index|
482
+ index.name == options[:name].to_s ||
483
+ Array(index.columns).map(&:to_s) == Array(options[:column]).map(&:to_s)
484
+ end
485
+
486
+ if index_def
487
+ existing_options = [:name, :columns, :unique, :where, :type, :using, :opclasses].map do |option|
488
+ [option, index_def.public_send(option)] if index_def.respond_to?(option)
489
+ end.compact.to_h
490
+
491
+ @removed_indexes << IndexDefinition.new(table: table_name, **existing_options)
484
492
  end
485
493
  end
486
494
 
@@ -597,15 +605,14 @@ module OnlineMigrations
597
605
  if Utils.developer_env? && (target_version = OnlineMigrations.config.target_version)
598
606
  target_version.to_s
599
607
  else
600
- # For rails 6.0+ we can use connection.database_version
601
- pg_connection = connection.raw_connection
602
- database_version = pg_connection.server_version
603
- patch = database_version % 100
604
- database_version /= 100
605
- minor = database_version % 100
606
- database_version /= 100
607
- major = database_version
608
- "#{major}.#{minor}.#{patch}"
608
+ database_version = connection.select_value("SHOW server_version_num").to_i
609
+ major = database_version / 10000
610
+ if database_version >= 100000
611
+ minor = database_version % 10000
612
+ else
613
+ minor = (database_version % 10000) / 100
614
+ end
615
+ "#{major}.#{minor}"
609
616
  end
610
617
 
611
618
  Gem::Version.new(version)
@@ -745,8 +752,7 @@ module OnlineMigrations
745
752
 
746
753
  def index_corruption?
747
754
  postgresql_version >= Gem::Version.new("14.0") &&
748
- postgresql_version < Gem::Version.new("14.4") &&
749
- !Utils.developer_env?
755
+ postgresql_version < Gem::Version.new("14.4")
750
756
  end
751
757
 
752
758
  def run_custom_checks(method, args)
@@ -30,10 +30,7 @@ module OnlineMigrations
30
30
  return false if where != other.where
31
31
  return false if other.respond_to?(:opclasses) && opclasses != other.opclasses
32
32
 
33
- case [unique, other.unique]
34
- when [true, true]
35
- columns == other.columns
36
- when [true, false]
33
+ if unique && !other.unique
37
34
  false
38
35
  else
39
36
  prefix?(self, other)
@@ -69,8 +69,9 @@ module OnlineMigrations
69
69
  def renamed_tables
70
70
  @renamed_tables ||= begin
71
71
  table_renames = OnlineMigrations.config.table_renames
72
+ views = connection.views
72
73
  table_renames.select do |old_name, _|
73
- connection.views.include?(old_name)
74
+ views.include?(old_name)
74
75
  end
75
76
  end
76
77
  end
@@ -78,8 +79,9 @@ module OnlineMigrations
78
79
  def renamed_columns
79
80
  @renamed_columns ||= begin
80
81
  column_renames = OnlineMigrations.config.column_renames
82
+ views = connection.views
81
83
  column_renames.select do |table_name, _|
82
- connection.views.include?(table_name)
84
+ views.include?(table_name)
83
85
  end
84
86
  end
85
87
  end
@@ -85,9 +85,13 @@ module OnlineMigrations
85
85
 
86
86
  conditions = columns_and_values.map do |(column_name, value)|
87
87
  value = Arel.sql(value.call.to_s) if value.is_a?(Proc)
88
- arel_column = model.arel_table[column_name]
89
- arel_column.not_eq(value).or(arel_column.eq(nil))
90
- end
88
+
89
+ # Ignore subqueries in conditions
90
+ unless value.is_a?(Arel::Nodes::SqlLiteral) && value.to_s =~ /select\s+/i
91
+ arel_column = model.arel_table[column_name]
92
+ arel_column.not_eq(value).or(arel_column.eq(nil))
93
+ end
94
+ end.compact
91
95
 
92
96
  batch_relation = model.where(conditions.inject(:and))
93
97
  batch_relation = yield batch_relation if block_given?
@@ -404,7 +408,7 @@ module OnlineMigrations
404
408
  batch_options = options.extract!(:batch_size, :batch_column_name, :progress, :pause_ms)
405
409
 
406
410
  if column_exists?(table_name, column_name)
407
- Utils.say("Column was not created because it already exists (this may be due to an aborted migration "\
411
+ Utils.say("Column was not created because it already exists (this may be due to an aborted migration " \
408
412
  "or similar) table_name: #{table_name}, column_name: #{column_name}")
409
413
  else
410
414
  transaction do
@@ -655,7 +659,7 @@ module OnlineMigrations
655
659
  schema = __schema_for_table(table_name)
656
660
 
657
661
  if __index_valid?(index_name, schema: schema)
658
- Utils.say("Index was not created because it already exists (this may be due to an aborted migration "\
662
+ Utils.say("Index was not created because it already exists (this may be due to an aborted migration " \
659
663
  "or similar): table_name: #{table_name}, column_name: #{column_name}")
660
664
  return
661
665
  else
@@ -699,7 +703,7 @@ module OnlineMigrations
699
703
  end
700
704
  end
701
705
  else
702
- Utils.say("Index was not removed because it does not exist (this may be due to an aborted migration "\
706
+ Utils.say("Index was not removed because it does not exist (this may be due to an aborted migration " \
703
707
  "or similar): table_name: #{table_name}, column_name: #{column_names}")
704
708
  end
705
709
  end
@@ -768,7 +772,7 @@ module OnlineMigrations
768
772
  constraint_name = __check_constraint_name(table_name, expression: expression, **options)
769
773
 
770
774
  if __check_constraint_exists?(table_name, constraint_name)
771
- Utils.say("Check constraint was not created because it already exists (this may be due to an aborted migration "\
775
+ Utils.say("Check constraint was not created because it already exists (this may be due to an aborted migration " \
772
776
  "or similar) table_name: #{table_name}, expression: #{expression}, constraint name: #{constraint_name}")
773
777
  else
774
778
  query = "ALTER TABLE #{table_name} ADD CONSTRAINT #{constraint_name} CHECK (#{expression})"
@@ -820,6 +824,29 @@ module OnlineMigrations
820
824
  end
821
825
  end
822
826
 
827
+ # @private
828
+ def pk_and_sequence_for(table)
829
+ views = self.views
830
+
831
+ table_renames = OnlineMigrations.config.table_renames
832
+ renamed_tables = table_renames.select do |old_name, _|
833
+ views.include?(old_name)
834
+ end
835
+
836
+ column_renames = OnlineMigrations.config.column_renames
837
+ renamed_columns = column_renames.select do |table_name, _|
838
+ views.include?(table_name)
839
+ end
840
+
841
+ if renamed_tables.key?(table)
842
+ super(renamed_tables[table])
843
+ elsif renamed_columns.key?(table)
844
+ super("#{table}_column_rename")
845
+ else
846
+ super
847
+ end
848
+ end
849
+
823
850
  # Disables statement timeout while executing &block
824
851
  #
825
852
  # Long-running migrations may take more than the timeout allowed by the database.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OnlineMigrations
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.2"
5
5
  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.5.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - fatkodima
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-23 00:00:00.000000000 Z
11
+ date: 2022-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord