class OnlineMigrations::CommandChecker

@private

Attributes

direction[RW]

Public Class Methods

new(migration) click to toggle source
# File lib/online_migrations/command_checker.rb, line 12
def initialize(migration)
  @migration = migration
  @safe = false
  @new_tables = []
  @lock_timeout_checked = false
  @foreign_key_tables = Set.new
  @removed_indexes = []
end

Public Instance Methods

check(command, *args, &block) click to toggle source
# File lib/online_migrations/command_checker.rb, line 29
def check(command, *args, &block)
  check_database_version
  check_lock_timeout

  unless safe?
    do_check(command, *args, &block)

    run_custom_checks(command, args)

    if @foreign_key_tables.count { |t| !new_table?(t) } > 1
      raise_error :multiple_foreign_keys
    end
  end

  true
end
safety_assured() { || ... } click to toggle source
# File lib/online_migrations/command_checker.rb, line 21
def safety_assured
  prev_value = @safe
  @safe = true
  yield
ensure
  @safe = prev_value
end

Private Instance Methods

add_belongs_to(table_name, ref_name, **options)
Alias for: add_reference
add_check_constraint(table_name, expression, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 502
def add_check_constraint(table_name, expression, **options)
  if !new_or_small_table?(table_name) && options[:validate] != false
    name = options[:name] || check_constraint_name(table_name, expression)

    raise_error :add_check_constraint,
      add_code: command_str(:add_check_constraint, table_name, expression, **options.merge(validate: false)),
      validate_code: command_str(:validate_check_constraint, table_name, name: name)
  end
end
add_column(table_name, column_name, type, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 174
def add_column(table_name, column_name, type, **options)
  default = options[:default]
  volatile_default = false
  if !new_or_small_table?(table_name) && !default.nil? &&
     (postgresql_version < Gem::Version.new("11") || (volatile_default = Utils.volatile_default?(connection, type, default)))

    raise_error :add_column_with_default,
      code: command_str(:add_column_with_default, table_name, column_name, type, options),
      not_null: options[:null] == false,
      volatile_default: volatile_default
  end

  if type == :json
    raise_error :add_column_json,
      code: command_str(:add_column, table_name, column_name, :jsonb, options)
  end

  check_inheritance_column(table_name, column_name, default)

  type = :bigint if type == :integer && options[:limit] == 8
  check_mismatched_foreign_key_type(table_name, column_name, type)
end
add_column_with_default(table_name, column_name, type, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 197
def add_column_with_default(table_name, column_name, type, **options)
  if type == :json
    raise_error :add_column_json,
      code: command_str(:add_column_with_default, table_name, column_name, :jsonb, options)
  end

  check_inheritance_column(table_name, column_name, options[:default])

  type = :bigint if type == :integer && options[:limit] == 8
  check_mismatched_foreign_key_type(table_name, column_name, type)
end
add_foreign_key(from_table, to_table, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 482
def add_foreign_key(from_table, to_table, **options)
  if !new_or_small_table?(from_table)
    validate = options.fetch(:validate, true)

    if validate
      raise_error :add_foreign_key,
        add_code: command_str(:add_foreign_key, from_table, to_table, **options.merge(validate: false)),
        validate_code: command_str(:validate_foreign_key, from_table, to_table)
    end
  end

  @foreign_key_tables << to_table.to_s
end
add_index(table_name, column_name, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 442
def add_index(table_name, column_name, **options)
  if options[:using].to_s == "hash" && postgresql_version < Gem::Version.new("10")
    raise_error :add_hash_index
  end

  if !new_or_small_table?(table_name)
    if options[:algorithm] != :concurrently
      raise_error :add_index,
        command: command_str(:add_index, table_name, column_name, **options.merge(algorithm: :concurrently))
    end

    if @removed_indexes.any?
      index = IndexDefinition.new(table: table_name, columns: column_name, **options)
      existing_indexes = connection.indexes(table_name)

      @removed_indexes.each do |removed_index|
        next unless removed_index.intersect?(index)

        unless existing_indexes.any? { |existing_index| removed_index.covered_by?(existing_index) }
          raise_error :replace_index
        end
      end
    end
  end
end
add_not_null_constraint(table_name, column_name, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 521
def add_not_null_constraint(table_name, column_name, **options)
  if !new_or_small_table?(table_name) && options[:validate] != false
    raise_error :add_not_null_constraint,
      add_code: command_str(:add_not_null_constraint, table_name, column_name, **options.merge(validate: false)),
      validate_code: command_str(:validate_not_null_constraint, table_name, column_name, **options.except(:validate))
  end
end
add_reference(table_name, ref_name, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 403
def add_reference(table_name, ref_name, **options)
  # Always added by default in 5.0+
  index = options.fetch(:index) { Utils.ar_version >= 5.0 }

  if index.is_a?(Hash) && index[:using].to_s == "hash" && postgresql_version < Gem::Version.new("10")
    raise_error :add_hash_index
  end

  concurrently_set = index.is_a?(Hash) && index[:algorithm] == :concurrently
  bad_index = index && !concurrently_set

  foreign_key = options.fetch(:foreign_key, false)

  if foreign_key
    foreign_table_name = Utils.foreign_table_name(ref_name, options)
    @foreign_key_tables << foreign_table_name.to_s
  end

  validate_foreign_key = !foreign_key.is_a?(Hash) ||
                         (!foreign_key.key?(:validate) || foreign_key[:validate] == true)
  bad_foreign_key = foreign_key && validate_foreign_key

  if !new_or_small_table?(table_name) && (bad_index || bad_foreign_key)
    raise_error :add_reference,
      code: command_str(:add_reference_concurrently, table_name, ref_name, **options),
      bad_index: bad_index,
      bad_foreign_key: bad_foreign_key
  end

  unless options[:polymorphic]
    type = options[:type] || (Utils.ar_version >= 5.1 ? :bigint : :integer)
    column_name = "#{ref_name}_id"

    foreign_key_options = foreign_key.is_a?(Hash) ? foreign_key : {}
    check_mismatched_foreign_key_type(table_name, column_name, type, **foreign_key_options)
  end
end
Also aliased as: add_belongs_to
add_text_limit_constraint(table_name, column_name, limit, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 529
def add_text_limit_constraint(table_name, column_name, limit, **options)
  if !new_or_small_table?(table_name) && options[:validate] != false
    raise_error :add_text_limit_constraint,
      add_code: command_str(:add_text_limit_constraint, table_name, column_name, limit, **options.merge(validate: false)),
      validate_code: command_str(:validate_text_limit_constraint, table_name, column_name, **options.except(:validate))
  end
end
add_timestamps(table_name, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 390
def add_timestamps(table_name, **options)
  volatile_default = false
  if !new_or_small_table?(table_name) && !options[:default].nil? &&
     (postgresql_version < Gem::Version.new("11") || (volatile_default = Utils.volatile_default?(connection, :datetime, options[:default])))

    raise_error :add_timestamps_with_default,
      code: [command_str(:add_column_with_default, table_name, :created_at, :datetime, options),
             command_str(:add_column_with_default, table_name, :updated_at, :datetime, options)].join("\n    "),
      not_null: options[:null] == false,
      volatile_default: volatile_default
  end
end
change_column(table_name, column_name, type, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 221
def change_column(table_name, column_name, type, **options)
  return if new_table?(table_name)

  type = type.to_sym

  existing_column = column_for(table_name, column_name)
  if existing_column
    existing_type = existing_column.type.to_sym

    # To get a list of binary-coercible types:
    #
    # SELECT stype.typname AS source, ttype.typname AS target
    # FROM pg_cast
    #   INNER JOIN pg_type stype ON pg_cast.castsource = stype.oid
    #   INNER JOIN pg_type ttype ON pg_cast.casttarget = ttype.oid
    # WHERE castmethod = 'b'
    # ORDER BY 1, 2

    # https://www.postgresql.org/docs/release/9.2.0/#AEN124164

    safe =
      case type
      when :string
        # safe to increase limit or remove it
        # not safe to decrease limit or add a limit
        case existing_type
        when :string
          !options[:limit] || (existing_column.limit && options[:limit] >= existing_column.limit)
        when :text, :xml
          !options[:limit]
        when :citext
          !options[:limit] && !indexed?(table_name, column_name)
        end
      when :text
        [:string, :text, :xml].include?(existing_type) ||
        (existing_type == :citext && !indexed?(table_name, column_name))
      when :citext
        [:string, :text].include?(existing_type) && !indexed?(table_name, column_name)
      when :bit_varying
        case existing_type
        when :bit
          !options[:limit]
        when :bit_varying
          # safe to increase limit or remove it
          # not safe to decrease limit or add a limit
          !options[:limit] || (existing_column.limit && options[:limit] >= existing_column.limit)
        end
      when :numeric, :decimal
        # numeric and decimal are equivalent and can be used interchangably
        [:numeric, :decimal].include?(existing_type) &&
        (
          (
            # unconstrained
            !options[:precision] && !options[:scale]
          ) || (
            # increased precision, same scale
            options[:precision] && existing_column.precision &&
            options[:precision] >= existing_column.precision &&
            options[:scale] == existing_column.scale
          )
        )
      when :datetime, :timestamp, :timestamptz
        # precision for datetime
        # limit for timestamp, timestamptz
        precision = (type == :datetime ? options[:precision] : options[:limit]) || 6
        existing_precision = existing_column.precision || existing_column.limit || 6

        [:datetime, :timestamp, :timestamptz].include?(existing_type) &&
        precision >= existing_precision &&
        (type == existing_type ||
          (postgresql_version >= Gem::Version.new("12") &&
          connection.select_value("SHOW timezone") == "UTC"))
      when :interval
        precision = options[:precision] || options[:limit] || 6
        existing_precision = existing_column.precision || existing_column.limit || 6

        # PostgreSQL interval data type was added in https://github.com/rails/rails/pull/16919
        (existing_type == :interval || (Utils.ar_version < 6.1 && existing_column.sql_type.start_with?("interval"))) &&
        precision >= existing_precision
      when :inet
        existing_type == :cidr
      else
        type == existing_type &&
        options[:limit] == existing_column.limit &&
        options[:precision] == existing_column.precision &&
        options[:scale] == existing_column.scale
      end

    # unsafe to set NOT NULL for safe types
    if safe && existing_column.null && options[:null] == false
      raise_error :change_column_with_not_null
    end

    if !safe
      raise_error :change_column,
        initialize_change_code: command_str(:initialize_column_type_change, table_name, column_name, type, **options),
        backfill_code: command_str(:backfill_column_for_type_change, table_name, column_name, **options),
        finalize_code: command_str(:finalize_column_type_change, table_name, column_name),
        cleanup_code: command_str(:cleanup_change_column_type_concurrently, table_name, column_name),
        cleanup_down_code: command_str(:initialize_column_type_change, table_name, column_name, existing_type)
    end
  end
end
change_column_null(table_name, column_name, allow_null, default = nil, **) click to toggle source
# File lib/online_migrations/command_checker.rb, line 325
def change_column_null(table_name, column_name, allow_null, default = nil, **)
  if !allow_null && !new_or_small_table?(table_name)
    safe = false
    # In PostgreSQL 12+ you can add a check constraint to the table
    # and then "promote" it to NOT NULL for the column.
    if postgresql_version >= Gem::Version.new("12")
      safe = check_constraints(table_name).any? do |c|
        c["def"] == "CHECK ((#{column_name} IS NOT NULL))" ||
          c["def"] == "CHECK ((#{connection.quote_column_name(column_name)} IS NOT NULL))"
      end
    end

    if !safe
      constraint_name = "#{table_name}_#{column_name}_null"
      vars = {
        add_constraint_code: command_str(:add_not_null_constraint, table_name, column_name, name: constraint_name, validate: false),
        validate_constraint_code: command_str(:validate_not_null_constraint, table_name, column_name, name: constraint_name),
        remove_constraint_code: nil,
        table_name: table_name,
        column_name: column_name,
        default: default,
      }

      if postgresql_version >= Gem::Version.new("12")
        vars[:remove_constraint_code] = command_str(:remove_check_constraint, table_name, name: constraint_name)
        vars[:change_column_null_code] = command_str(:change_column_null, table_name, column_name, false)
      end

      raise_error :change_column_null, **vars
    end
  end
end
change_table(*) click to toggle source
# File lib/online_migrations/command_checker.rb, line 162
def change_table(*)
  raise_error :change_table, header: "Possibly dangerous operation"
end
check_columns_removal(command, *args, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 358
def check_columns_removal(command, *args, **options)
  case command
  when :remove_column
    table_name, column_name = args
    columns = [column_name]
  when :remove_columns
    table_name, *columns = args
  when :remove_timestamps
    table_name = args[0]
    columns = ["created_at", "updated_at"]
  else
    table_name, reference = args
    columns = ["#{reference}_id"]
    columns << "#{reference}_type" if options[:polymorphic]
  end

  columns = columns.map(&:to_s)

  if !new_table?(table_name)
    indexes = connection.indexes(table_name).select do |index|
      (index.columns & columns).any?
    end

    raise_error :remove_column,
      model: table_name.to_s.classify,
      columns: columns.inspect,
      command: command_str(command, *args, options),
      table_name: table_name.inspect,
      indexes: indexes.map { |i| i.name.to_sym.inspect }
  end
end
check_constraint_name(table_name, expression) click to toggle source
# File lib/online_migrations/command_checker.rb, line 676
def check_constraint_name(table_name, expression)
  identifier = "#{table_name}_#{expression}_chk"
  hashed_identifier = OpenSSL::Digest::SHA256.hexdigest(identifier).first(10)

  "chk_rails_#{hashed_identifier}"
end
check_constraints(table_name) click to toggle source
# File lib/online_migrations/command_checker.rb, line 683
      def check_constraints(table_name)
        constraints_query = <<-SQL.strip_heredoc
          SELECT pg_get_constraintdef(oid) AS def
          FROM pg_constraint
          WHERE contype = 'c'
            AND convalidated
            AND conrelid = #{connection.quote(table_name)}::regclass
        SQL

        connection.select_all(constraints_query).to_a
      end
check_database_version() click to toggle source
# File lib/online_migrations/command_checker.rb, line 47
def check_database_version
  return if defined?(@database_version_checked)

  adapter = connection.adapter_name
  case adapter
  when /postg/i
    if postgresql_version < Gem::Version.new("9.6")
      raise "#{adapter} < 9.6 is not supported"
    end
  else
    raise "#{adapter} is not supported"
  end

  @database_version_checked = true
end
check_for_hash_indexes(&block) click to toggle source
# File lib/online_migrations/command_checker.rb, line 565
def check_for_hash_indexes(&block)
  indexes = collect_indexes(&block)
  if indexes.any? { |index| index.using == "hash" }
    raise_error :add_hash_index
  end
end
check_inheritance_column(table_name, column_name, default) click to toggle source
# File lib/online_migrations/command_checker.rb, line 695
def check_inheritance_column(table_name, column_name, default)
  if column_name.to_s == ActiveRecord::Base.inheritance_column && !default.nil?
    raise_error :add_inheritance_column,
      table_name: table_name, column_name: column_name,
      model: table_name.to_s.classify, subclass: default
  end
end
check_lock_timeout() click to toggle source
# File lib/online_migrations/command_checker.rb, line 63
def check_lock_timeout
  limit = OnlineMigrations.config.lock_timeout_limit

  if limit && !@lock_timeout_checked
    lock_timeout = connection.select_value("SHOW lock_timeout")
    lock_timeout_sec = timeout_to_sec(lock_timeout)

    if lock_timeout_sec == 0
      Utils.warn("DANGER: No lock timeout set")
    elsif lock_timeout_sec > limit
      Utils.warn("DANGER: Lock timeout is longer than #{limit} seconds: #{lock_timeout}")
    end

    @lock_timeout_checked = true
  end
end
check_mismatched_foreign_key_type(table_name, column_name, type, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 703
def check_mismatched_foreign_key_type(table_name, column_name, type, **options)
  column_name = column_name.to_s
  ref_name = column_name.sub(/_id\z/, "")

  if like_foreign_key?(column_name, type)
    foreign_table_name = Utils.foreign_table_name(ref_name, options)

    if connection.table_exists?(foreign_table_name)
      primary_key = options[:primary_key] || connection.primary_key(foreign_table_name)
      primary_key_column = column_for(foreign_table_name, primary_key)

      if primary_key_column && type != primary_key_column.sql_type.to_sym
        raise_error :mismatched_foreign_key_type,
          table_name: table_name, column_name: column_name
      end
    end
  end
end
collect_foreign_keys(&block) click to toggle source
# File lib/online_migrations/command_checker.rb, line 559
def collect_foreign_keys(&block)
  collector = ForeignKeysCollector.new
  collector.collect(&block)
  @foreign_key_tables |= collector.referenced_tables
end
collect_indexes(&block) click to toggle source
# File lib/online_migrations/command_checker.rb, line 572
def collect_indexes(&block)
  collector = IndexesCollector.new
  collector.collect(&block)
  collector.indexes
end
column_for(table_name, column_name) click to toggle source
# File lib/online_migrations/command_checker.rb, line 731
def column_for(table_name, column_name)
  connection.columns(table_name).find { |column| column.name == column_name.to_s }
end
command_str(command, *args) click to toggle source
# File lib/online_migrations/command_checker.rb, line 636
def command_str(command, *args)
  arg_list = args[0..-2].map(&:inspect)

  last_arg = args.last
  if last_arg.is_a?(Hash)
    if last_arg.any?
      arg_list << last_arg.map do |k, v|
        case v
        when Hash
          if v.empty?
            "#{k}: {}"
          else
            # pretty index: { algorithm: :concurrently }
            "#{k}: { #{v.map { |k2, v2| "#{k2}: #{v2.inspect}" }.join(', ')} }"
          end
        when Array, Numeric, String, Symbol, TrueClass, FalseClass
          "#{k}: #{v.inspect}"
        else
          "<paste value here>"
        end
      end.join(", ")
    end
  else
    arg_list << last_arg.inspect
  end

  "#{command} #{arg_list.join(', ')}"
end
connection() click to toggle source
# File lib/online_migrations/command_checker.rb, line 608
def connection
  @migration.connection
end
create_join_table(table1, table2, **options, &block) click to toggle source
# File lib/online_migrations/command_checker.rb, line 142
def create_join_table(table1, table2, **options, &block)
  table_name = options[:table_name] || derive_join_table_name(table1, table2)
  create_table(table_name, **options, &block)
end
create_table(table_name, **options, &block) click to toggle source
# File lib/online_migrations/command_checker.rb, line 126
def create_table(table_name, **options, &block)
  raise_error :create_table if options[:force]

  # Probably, it would be good idea to also check for foreign keys
  # with short integer types, and for mismatched primary key vs foreign key types.
  # But I think this check is enough for now.
  raise_error :short_primary_key_type if short_primary_key_type?(options)

  if block
    collect_foreign_keys(&block)
    check_for_hash_indexes(&block) if postgresql_version < Gem::Version.new("10")
  end

  @new_tables << table_name.to_s
end
crud_blocked?() click to toggle source
# File lib/online_migrations/command_checker.rb, line 665
      def crud_blocked?
        locks_query = <<-SQL.strip_heredoc
          SELECT relation::regclass::text
          FROM pg_locks
          WHERE mode IN ('ShareLock', 'ShareRowExclusiveLock', 'ExclusiveLock', 'AccessExclusiveLock')
            AND pid = pg_backend_pid()
        SQL

        connection.select_values(locks_query).any?
      end
derive_join_table_name(table1, table2) click to toggle source

From ActiveRecord

# File lib/online_migrations/command_checker.rb, line 736
def derive_join_table_name(table1, table2)
  [table1.to_s, table2.to_s].sort.join("\0").gsub(/^(.*_)(.+)\0\1(.+)/, '\1\2_\3').tr("\0", "_")
end
do_check(command, *args, **options, &block) click to toggle source
# File lib/online_migrations/command_checker.rb, line 112
def do_check(command, *args, **options, &block)
  case command
  when :remove_column, :remove_columns, :remove_timestamps, :remove_reference, :remove_belongs_to
    check_columns_removal(command, *args, **options)
  else
    if respond_to?(command, true)
      send(command, *args, **options, &block)
    else
      # assume it is safe
      true
    end
  end
end
drop_join_table(table1, table2, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 157
def drop_join_table(table1, table2, **options)
  table_name = options[:table_name] || derive_join_table_name(table1, table2)
  drop_table(table_name, **options)
end
drop_table(table_name, **_options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 147
def drop_table(table_name, **_options)
  foreign_keys = connection.foreign_keys(table_name)
  referenced_tables = foreign_keys.map(&:to_table).uniq
  referenced_tables.delete(table_name.to_s) # ignore self references

  if referenced_tables.count { |t| !new_table?(t) } > 1
    raise_error :drop_table_multiple_foreign_keys
  end
end
exec_query(*)
Alias for: execute
execute(*) click to toggle source
# File lib/online_migrations/command_checker.rb, line 537
def execute(*)
  raise_error :execute, header: "Possibly dangerous operation"
end
Also aliased as: exec_query
indexed?(table_name, column_name) click to toggle source
# File lib/online_migrations/command_checker.rb, line 727
def indexed?(table_name, column_name)
  connection.indexes(table_name).any? { |index| index.columns.include?(column_name.to_s) }
end
like_foreign_key?(column_name, type) click to toggle source
# File lib/online_migrations/command_checker.rb, line 722
def like_foreign_key?(column_name, type)
  column_name.end_with?("_id") &&
    [:integer, :bigint, :serial, :bigserial, :uuid].include?(type)
end
new_or_small_table?(table_name) click to toggle source
# File lib/online_migrations/command_checker.rb, line 578
def new_or_small_table?(table_name)
  small_tables = OnlineMigrations.config.small_tables

  new_table?(table_name) ||
    small_tables.include?(table_name.to_s)
end
new_table?(table_name) click to toggle source
# File lib/online_migrations/command_checker.rb, line 585
def new_table?(table_name)
  @new_tables.include?(table_name.to_s)
end
postgresql_version() click to toggle source
# File lib/online_migrations/command_checker.rb, line 589
def postgresql_version
  version =
    if Utils.developer_env? && (target_version = OnlineMigrations.config.target_version)
      target_version.to_s
    else
      # For rails 6.0+ we can use connection.database_version
      pg_connection = connection.raw_connection
      database_version = pg_connection.server_version
      patch = database_version % 100
      database_version /= 100
      minor = database_version % 100
      database_version /= 100
      major = database_version
      "#{major}.#{minor}.#{patch}"
    end

  Gem::Version.new(version)
end
raise_error(message_key, header: nil, **vars) click to toggle source
# File lib/online_migrations/command_checker.rb, line 612
def raise_error(message_key, header: nil, **vars)
  return if !OnlineMigrations.config.check_enabled?(message_key, version: version)

  template = OnlineMigrations.config.error_messages.fetch(message_key)

  vars[:migration_name] = @migration.name
  vars[:migration_parent] = Utils.migration_parent_string
  vars[:model_parent] = Utils.model_parent_string
  vars[:ar_version] = Utils.ar_version

  if RUBY_VERSION >= "2.6"
    message = ERB.new(template, trim_mode: "<>").result_with_hash(vars)
  else
    # `result_with_hash` was added in ruby 2.5
    b = TOPLEVEL_BINDING.dup
    vars.each_pair do |key, value|
      b.local_variable_set(key, value)
    end
    message = ERB.new(template, nil, "<>").result(b)
  end

  @migration.stop!(message, header: header || "Dangerous operation detected")
end
remove_index(table_name, column_name = nil, **options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 468
def remove_index(table_name, column_name = nil, **options)
  options[:column] ||= column_name

  if options[:algorithm] != :concurrently && !new_or_small_table?(table_name)
    raise_error :remove_index,
      command: command_str(:remove_index, table_name, **options.merge(algorithm: :concurrently))
  end

  if options[:column] || options[:name]
    options[:column] ||= connection.indexes(table_name).find { |index| index.name == options[:name].to_s }
    @removed_indexes << IndexDefinition.new(table: table_name, columns: options.delete(:column), **options)
  end
end
rename_column(table_name, column_name, new_column, **) click to toggle source
# File lib/online_migrations/command_checker.rb, line 209
def rename_column(table_name, column_name, new_column, **)
  if !new_table?(table_name)
    raise_error :rename_column,
      table_name: table_name,
      column_name: column_name,
      new_column: new_column,
      model: table_name.to_s.classify,
      partial_writes: Utils.ar_partial_writes?,
      partial_writes_setting: Utils.ar_partial_writes_setting
  end
end
rename_table(table_name, new_name, **) click to toggle source
# File lib/online_migrations/command_checker.rb, line 166
def rename_table(table_name, new_name, **)
  if !new_table?(table_name)
    raise_error :rename_table,
      table_name: table_name,
      new_name: new_name
  end
end
run_custom_checks(method, args) click to toggle source
# File lib/online_migrations/command_checker.rb, line 740
def run_custom_checks(method, args)
  OnlineMigrations.config.checks.each do |options, check|
    if !options[:start_after] || version > options[:start_after]
      @migration.instance_exec(method, args, &check)
    end
  end
end
safe?() click to toggle source
# File lib/online_migrations/command_checker.rb, line 101
def safe?
  @safe ||
    ENV["SAFETY_ASSURED"] ||
    (direction == :down && !OnlineMigrations.config.check_down) ||
    version <= OnlineMigrations.config.start_after
end
short_primary_key_type?(options) click to toggle source
# File lib/online_migrations/command_checker.rb, line 542
def short_primary_key_type?(options)
  pk_type =
    case options[:id]
    when false
      nil
    when Hash
      options[:id][:type]
    when :primary_key, nil
      # default type is used
      connection.native_database_types[:primary_key].split.first
    else
      options[:id]
    end

  pk_type && !["bigserial", "bigint", "uuid"].include?(pk_type.to_s)
end
timeout_to_sec(timeout) click to toggle source
# File lib/online_migrations/command_checker.rb, line 80
def timeout_to_sec(timeout)
  units = {
    "us" => 10**-6,
    "ms" => 10**-3,
    "s" => 1,
    "min" => 60,
    "h" => 60 * 60,
    "d" => 60 * 60 * 24,
  }

  timeout_sec = timeout.to_i

  units.each do |k, v|
    if timeout.end_with?(k)
      timeout_sec *= v
      break
    end
  end
  timeout_sec
end
validate_check_constraint(*)
Alias for: validate_constraint
validate_constraint(*) click to toggle source
# File lib/online_migrations/command_checker.rb, line 512
def validate_constraint(*)
  if crud_blocked?
    raise_error :validate_constraint
  end
end
validate_foreign_key(*) click to toggle source
# File lib/online_migrations/command_checker.rb, line 496
def validate_foreign_key(*)
  if crud_blocked?
    raise_error :validate_foreign_key
  end
end
validate_not_null_constraint(*)
Alias for: validate_constraint
validate_text_limit_constraint(*)
Alias for: validate_constraint
version() click to toggle source
# File lib/online_migrations/command_checker.rb, line 108
def version
  @migration.version || @migration.class.version
end