Module: OnlineMigrations::BackgroundSchemaMigrations::MigrationHelpers

Included in:
SchemaStatements
Defined in:
lib/online_migrations/background_schema_migrations/migration_helpers.rb

Instance Method Summary collapse

Instance Method Details

#add_index_in_background(table_name, column_name, **options) ⇒ Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/online_migrations/background_schema_migrations/migration_helpers.rb', line 6

def add_index_in_background(table_name, column_name, **options)
  migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name)

  options[:algorithm] = :concurrently
  index, algorithm, if_not_exists = add_index_options(table_name, column_name, **options)

  # Need to check this first, because `index_exists?` does not check for `:where`s.
  if index_name_exists?(table_name, index.name)
    Utils.raise_or_say(<<~MSG)
      Index creation was not enqueued because the index with name '#{index.name}' already exists.
      This can be due to an aborted migration or you need to explicitly provide another name
      via `:name` option.
    MSG
    return
  end

  if index_exists?(table_name, column_name, **options)
    Utils.raise_or_say("Index creation was not enqueued because the index already exists.")
    return
  end

  create_index = ActiveRecord::ConnectionAdapters::CreateIndexDefinition.new(index, algorithm, if_not_exists)
  schema_creation = ActiveRecord::ConnectionAdapters::PostgreSQL::SchemaCreation.new(self)
  definition = schema_creation.accept(create_index)

  enqueue_background_schema_migration(index.name, table_name, definition: definition, **migration_options)
end

#enqueue_background_schema_migration(name, table_name, **options) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/online_migrations/background_schema_migrations/migration_helpers.rb', line 91

def enqueue_background_schema_migration(name, table_name, **options)
  if options[:connection_class_name].nil? && Utils.multiple_databases?
    raise ArgumentError, "You must pass a :connection_class_name when using multiple databases."
  end

  migration = create_background_schema_migration(name, table_name, **options)

  run_inline = OnlineMigrations.config.run_background_migrations_inline
  if run_inline && run_inline.call
    runner = MigrationRunner.new(migration)
    runner.run
  end

  migration
end

#ensure_background_schema_migration_succeeded(migration_name) ⇒ Object

Ensures that the background schema migration with the provided migration name succeeded.

If the enqueued migration was not found in development (probably when resetting a dev environment followed by db:migrate), then a log warning is printed. If enqueued migration was not found in production, then the error is raised. If enqueued migration was found but is not succeeded, then the error is raised.

Examples:

ensure_background_schema_migration_succeeded("index_users_on_email")

Parameters:

  • migration_name (String, Symbol)

    Background schema migration name



80
81
82
83
84
85
86
87
88
89
# File 'lib/online_migrations/background_schema_migrations/migration_helpers.rb', line 80

def ensure_background_schema_migration_succeeded(migration_name)
  migration = Migration.parents.find_by(migration_name: migration_name)

  if migration.nil?
    Utils.raise_in_prod_or_say_in_dev("Could not find background schema migration: '#{migration_name}'")
  elsif !migration.succeeded?
    raise "Expected background schema migration '#{migration_name}' to be marked as 'succeeded', " \
          "but it is '#{migration.status}'."
  end
end

#remove_index_in_background(table_name, column_name = nil, name:, **options) ⇒ Object

Raises:

  • (ArgumentError)


34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/online_migrations/background_schema_migrations/migration_helpers.rb', line 34

def remove_index_in_background(table_name, column_name = nil, name:, **options)
  raise ArgumentError, "Index name must be specified" if name.blank?

  migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name)

  if !index_exists?(table_name, column_name, **options, name: name)
    Utils.raise_or_say("Index deletion was not enqueued because the index does not exist.")
    return
  end

  definition = "DROP INDEX CONCURRENTLY IF EXISTS #{quote_column_name(name)}"
  enqueue_background_schema_migration(name, table_name, definition: definition, **migration_options)
end

#validate_constraint_in_background(table_name, constraint_name, **options) ⇒ Object



60
61
62
63
64
65
66
# File 'lib/online_migrations/background_schema_migrations/migration_helpers.rb', line 60

def validate_constraint_in_background(table_name, constraint_name, **options)
  definition = <<~SQL.squish
    ALTER TABLE #{quote_table_name(table_name)}
    VALIDATE CONSTRAINT #{quote_table_name(constraint_name)}
  SQL
  enqueue_background_schema_migration(constraint_name, table_name, definition: definition, **options)
end

#validate_foreign_key_in_background(from_table, to_table = nil, **options) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
# File 'lib/online_migrations/background_schema_migrations/migration_helpers.rb', line 48

def validate_foreign_key_in_background(from_table, to_table = nil, **options)
  migration_options = options.extract!(:max_attempts, :statement_timeout, :connection_class_name)

  if !foreign_key_exists?(from_table, to_table, **options)
    Utils.raise_or_say("Foreign key validation was not enqueued because the foreign key does not exist.")
    return
  end

  fk_name_to_validate = foreign_key_for!(from_table, to_table: to_table, **options).name
  validate_constraint_in_background(from_table, fk_name_to_validate, **migration_options)
end