class RuboCop::Cop::PostgresMigrationCops::AddIndexesConcurrently

Check that indexes are added concurrently with disable_ddl_transaction! thoughtbot.com/blog/how-to-create-postgres-indexes-concurrently-in

@example

# bad
 class SomeTableMigrations < ActiveRecord::Migration
   def change
     add_column :table, :some_column_1, :integer, default: 0, null: false
     add_column :table, :other_column, :string
     add_column :table, :doneit_at, :datetime
     add_index  :table,
                :other_column,
                unique: true
   end
 end

# good
 class SomeTableMigrations < ActiveRecord::Migration
   disable_ddl_transaction!
   def change
     add_column :table, :some_column_1, :integer, default: 0, null: false
     add_column :table, :other_column, :string
     add_column :table, :doneit_at, :datetime
     add_index  :table,
                :other_column,
                unique: true,
                algorithm: :concurrently
     end
 end

Constants

CONCURRENTLY
IGNORE_DDL

Public Instance Methods

on_class(class_node) click to toggle source
# File lib/cops/add_indexes_concurrently.rb, line 39
def on_class(class_node)
  is_migration = class_node.children.any? { |n| is_migration?(n) }
  return unless is_migration

  index_nodes = find_index_methods(class_node)
  return unless creating_indexes?(index_nodes)

  ensure_disable_dll_transaction_offense(class_node, index_nodes)
  ensure_indexes_added_non_concurrently_offenses(index_nodes)
end

Private Instance Methods

concurrent_indexes?(index_nodes) click to toggle source
# File lib/cops/add_indexes_concurrently.rb, line 68
def concurrent_indexes?(index_nodes)
  index_nodes
    .select { |n| n.source.include?('concurrent') }
    .count
    .positive?
end
creating_indexes?(index_nodes) click to toggle source
# File lib/cops/add_indexes_concurrently.rb, line 52
def creating_indexes?(index_nodes)
  index_nodes.count.positive?
end
disable_ddl_transaction_declared?(node) click to toggle source
# File lib/cops/add_indexes_concurrently.rb, line 63
def disable_ddl_transaction_declared?(node)
  begins = find__begin node
  begins.any? { |b| b.children.any? { |n| has_disable_ddl?(n) } }
end
ensure_disable_dll_transaction_offense(class_node, index_nodes) click to toggle source
# File lib/cops/add_indexes_concurrently.rb, line 56
def ensure_disable_dll_transaction_offense(class_node, index_nodes)
  return if disable_ddl_transaction_declared?(class_node)

  has_concurrent = concurrent_indexes?(index_nodes)
  add_offense(class_node, message: IGNORE_DDL) if has_concurrent
end
ensure_indexes_added_non_concurrently_offenses(index_nodes) click to toggle source
# File lib/cops/add_indexes_concurrently.rb, line 75
def ensure_indexes_added_non_concurrently_offenses(index_nodes)
  index_nodes
    .reject { |n| n.source.include?('concurrently') }
    .to_a.each { |n| add_offense(n, message: CONCURRENTLY) }
end
find_index_methods(node) click to toggle source
# File lib/cops/add_indexes_concurrently.rb, line 81
def find_index_methods(node)
  sends = find__send node
  sends.select { |n| n.source.include?('add_index') }
end