Class: OnlineMigrations::BackgroundDataMigrations::CopyColumn

Inherits:
DataMigration
  • Object
show all
Defined in:
lib/online_migrations/background_data_migrations/copy_column.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from DataMigration

#after_cancel, #after_complete, #after_pause, #after_resume, #after_start, #after_stop, #around_process, #build_enumerator, collection_batch_size, named

Constructor Details

#initialize(table_name, copy_from, copy_to, model_name = nil, type_cast_functions = {}) ⇒ CopyColumn



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_data_migrations/copy_column.rb', line 9

def initialize(table_name, copy_from, copy_to, model_name = nil, type_cast_functions = {})
  @table_name = table_name

  if copy_from.is_a?(Array) && type_cast_functions && !type_cast_functions.is_a?(Hash)
    raise ArgumentError, "type_cast_functions must be a Hash"
  end

  @copy_from = Array.wrap(copy_from)
  @copy_to = Array.wrap(copy_to)

  if @copy_from.size != @copy_to.size
    raise ArgumentError, "Number of source and destination columns must match"
  end

  @model_name = model_name
  @model =
    if model_name.present?
      Object.const_get(model_name, false)
    else
      Utils.define_model(table_name)
    end

  @type_cast_functions = type_cast_functions
end

Instance Attribute Details

#copy_fromObject (readonly)

Returns the value of attribute copy_from.



7
8
9
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 7

def copy_from
  @copy_from
end

#copy_toObject (readonly)

Returns the value of attribute copy_to.



7
8
9
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 7

def copy_to
  @copy_to
end

#model_nameObject (readonly)

Returns the value of attribute model_name.



7
8
9
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 7

def model_name
  @model_name
end

#table_nameObject (readonly)

Returns the value of attribute table_name.



7
8
9
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 7

def table_name
  @table_name
end

#type_cast_functionsObject (readonly)

Returns the value of attribute type_cast_functions.



7
8
9
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 7

def type_cast_functions
  @type_cast_functions
end

Instance Method Details

#collectionObject



34
35
36
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 34

def collection
  @model.unscoped.in_batches(of: 100, use_ranges: true)
end

#countObject



59
60
61
62
63
64
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 59

def count
  # Exact counts are expensive on large tables, since PostgreSQL
  # needs to do a full scan. An estimated count should give a pretty decent
  # approximation of rows count in this case.
  Utils.estimated_count(@model.connection, table_name)
end

#process(relation) ⇒ Object



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/online_migrations/background_data_migrations/copy_column.rb', line 38

def process(relation)
  arel_table = relation.arel_table

  old_values = copy_from.map do |from_column|
    old_value = arel_table[from_column]
    if (type_cast_function = type_cast_functions[from_column])
      old_value =
        if type_cast_function.match?(/\A\w+\z/)
          Arel::Nodes::NamedFunction.new(type_cast_function, [old_value])
        else
          # We got a cast expression.
          Arel.sql(type_cast_function)
        end
    end
    old_value
  end

  updates = copy_to.zip(old_values).to_h { |to_column, old_value| [to_column, old_value] }
  relation.update_all(updates)
end