Module: LowCardTables::ActiveRecord::Migrations

Extended by:
ActiveSupport::Concern
Defined in:
lib/low_card_tables/active_record/migrations.rb

Overview

This module gets included into ::ActiveRecord::Migrations, and overrides key methods (using alias_method_chain) to add low-card support. Its job is to detect if a low-card table is being modified, and, if so:

  • Remove the all-columns unique index before the operation in question, and add it back afterwards

  • If a column has been removed, collapse any now-duplicate rows in question and update all referring tables

It also adds a single method to migrations, #change_low_card_table, which does nothing of its own rather than to call the passed block – but it does all the checking above at the start and end, and disables any such checking within the block. It thus gives you control over exactly when this happens.

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.with_low_card_support(table_name, options = { }, &block) ⇒ Object

Adds all the checking described in the comment on LowCardTables::ActiveRecord::Migrations for the given table name to the supplied block.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/low_card_tables/active_record/migrations.rb', line 87

def with_low_card_support(table_name, options = { }, &block)
  # Don't do this if we're already inside such a check -- this is needed because:
  #
  #    change_table :foo do |t|
  #      t.remove :bar
  #    end
  #
  # ...actually translates internally to a call to remove_column inside change_table, and, otherwise, we'll
  # try to do our work twice, which is bad news.
  (options, low_card_options) = partition_low_card_options(options)
  return block.call(options) if inside_migrations_check?

  low_card_model = low_card_model_to_use_for(table_name, low_card_options)
  return block.call(options) if (! low_card_model)

  with_migrations_check do
    without_unique_index(low_card_model, low_card_options) do
      with_removed_column_detection(low_card_model, low_card_options) do
        block.call(options)
      end
    end
  end
end

Instance Method Details

#add_column_with_low_card_support(table_name, column_name, type, options = {}) ⇒ Object

Overrides ::ActiveRecord::Migrations#add_column with low-cardinality support, as described in the comment for LowCardTables::ActiveRecord::Migrations.



30
31
32
33
34
# File 'lib/low_card_tables/active_record/migrations.rb', line 30

def add_column_with_low_card_support(table_name, column_name, type, options = {})
  ::LowCardTables::ActiveRecord::Migrations.with_low_card_support(table_name, options) do |new_options|
    add_column_without_low_card_support(table_name, column_name, type, options)
  end
end

#change_low_card_table(table_name, &block) ⇒ Object

Given the name of a low-card table and a block:

  • Removes the all-columns unique index for that low-card table;

  • Calls the block;

  • Looks for any removed columns, and, if so, collapses now-duplicate rows and updates all referrers;

  • Creates the all-columns unique index for that table.

While inside the block, none of the above checking will be performed against that table, as it otherwise would be if you call #add_column, #remove_column, #create_table, or #change_table. This thus gives you a scope in which to do what you need to do, without the all-columns index interfering.



71
72
73
74
75
# File 'lib/low_card_tables/active_record/migrations.rb', line 71

def change_low_card_table(table_name, &block)
  ::LowCardTables::ActiveRecord::Migrations.with_low_card_support(table_name, { :low_card => true }) do |new_options|
    block.call
  end
end

#change_table_with_low_card_support(table_name, options = { }, &block) ⇒ Object

Overrides ::ActiveRecord::Migrations#change_table with low-cardinality support, as described in the comment for LowCardTables::ActiveRecord::Migrations.



50
51
52
53
54
55
56
57
58
59
# File 'lib/low_card_tables/active_record/migrations.rb', line 50

def change_table_with_low_card_support(table_name, options = { }, &block)
  ::LowCardTables::ActiveRecord::Migrations.with_low_card_support(table_name, options) do |new_options|
    ar = method(:change_table_without_low_card_support).arity
    if ar > 1 || ar < -2
      change_table_without_low_card_support(table_name, new_options, &block)
    else
      change_table_without_low_card_support(table_name, &block)
    end
  end
end

#create_table_with_low_card_support(table_name, options = { }, &block) ⇒ Object

Overrides ::ActiveRecord::Migrations#create_table with low-cardinality support, as described in the comment for LowCardTables::ActiveRecord::Migrations.



22
23
24
25
26
# File 'lib/low_card_tables/active_record/migrations.rb', line 22

def create_table_with_low_card_support(table_name, options = { }, &block)
  ::LowCardTables::ActiveRecord::Migrations.with_low_card_support(table_name, options) do |new_options|
    create_table_without_low_card_support(table_name, new_options, &block)
  end
end

#remove_column_with_low_card_support(table_name, *column_names) ⇒ Object

Overrides ::ActiveRecord::Migrations#remove_column with low-cardinality support, as described in the comment for LowCardTables::ActiveRecord::Migrations.



38
39
40
41
42
43
44
45
46
# File 'lib/low_card_tables/active_record/migrations.rb', line 38

def remove_column_with_low_card_support(table_name, *column_names)
  options = column_names.pop if column_names[-1] && column_names[-1].kind_of?(Hash)
  ::LowCardTables::ActiveRecord::Migrations.with_low_card_support(table_name, options) do |new_options|
    args = [ table_name ]
    args += column_names
    args << new_options if new_options && new_options.size > 0
    remove_column_without_low_card_support(*args)
  end
end