class Cequel::Schema::TableDiffer

Utility object that calculates a `Patch` to transform one `Table` into another.

Currently this support adding columns, adding and removing indexes, and setting properties on the table. Any other changes are prohibited due to CQL limitation or data integrity concerns. A `InvalidSchemaMigration` will be raised if unsupported changes are detected.

Attributes

table_a[R]
table_b[R]

Public Class Methods

new(table_a, table_b) click to toggle source
# File lib/cequel/schema/table_differ.rb, line 13
          def initialize(table_a, table_b)
  @table_a = table_a
  @table_b = table_b
end

Public Instance Methods

call() click to toggle source

Returns a Patch that will transform table_a in to table_b.

# File lib/cequel/schema/table_differ.rb, line 20
def call
  (fail InvalidSchemaMigration, "Table renames are not supported") if
    table_a.name != table_b.name
  (fail InvalidSchemaMigration, "Changes to key structure is not allowed") if
    keys_changed?
  (fail InvalidSchemaMigration, "Type changes are not allowed") if any_types_changed?

  Patch.new(figure_changes)
end

Protected Instance Methods

added_columns() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 63
def added_columns
  table_b
    .data_columns
    .reject{|c_a| table_a.data_columns.any?{|c_b| c_b.name == c_a.name } }
end
added_indexes() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 69
def added_indexes
  table_b.columns
    .select(&:indexed?)
    .reject{|c| table_a.has_column?(c.name) &&
              table_a.column(c.name).indexed? } # ignore still indexed columns
end
any_types_changed?() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 83
def any_types_changed?
  table_a.columns
    .select{|c_a| table_b.has_column?(c_a.name) }
    .any?{|c_a| table_b.column(c_a.name).type != c_a.type}
end
cluster_keys_compatible?(key_a, key_b) click to toggle source
# File lib/cequel/schema/table_differ.rb, line 95
def cluster_keys_compatible?(key_a, key_b)
  return false if key_a.blank? or key_b.blank?

  key_a.type == key_b.type &&
    key_a.clustering_order == key_b.clustering_order
end
column_changes() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 46
def column_changes
  renames
    .map { |old_and_new_c| Patch::RenameColumn.new(table_b, *old_and_new_c) } +
    added_columns
      .map { |new_c| Patch::AddColumn.new(table_b, new_c) } +
    added_indexes
      .map { |col_with_new_idx| Patch::AddIndex.new(table_b, col_with_new_idx) } +
    dropped_indexes
      .map { |col_with_old_idx| Patch::DropIndex.new(table_b, col_with_old_idx) }
end
dropped_indexes() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 76
def dropped_indexes
  table_a.columns
    .select(&:indexed?)
    .reject{|c| !table_b.has_column?(c.name) } # ignore "dropped" columns
    .reject{|c| table_b.column(c.name).indexed? }
end
figure_changes() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 34
def figure_changes
  column_changes + property_changes
end
keys_changed?() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 89
def keys_changed?
  table_a.partition_key_columns != table_b.partition_key_columns ||
    table_a.clustering_columns.zip(table_b.clustering_columns)
      .any? { |ks| !cluster_keys_compatible?(*ks) }
end
properties_changed?() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 102
def properties_changed?
  p_a = table_a.properties.values
  p_b = table_b.properties.values

  ((p_a | p_b) - (p_a & p_b)).any?
end
property_changes() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 38
def property_changes
  if properties_changed? && table_b.properties.any?
    [Patch::SetTableProperties.new(table_b)]
  else
    []
  end
end
renames() click to toggle source
# File lib/cequel/schema/table_differ.rb, line 57
def renames
  table_a.clustering_columns
    .zip(table_b.clustering_columns)
    .select { |ks| ks[0].name != ks[1].name }
end