class Ridgepole::Diff def initialize(options = {}) @options = options end def diff(from, to) from = (from || {}).dup to = (to || {}).dup delta = {} to.dup.each do |table_name, to_attrs| next unless target?(table_name) if (from_table_name = (to_attrs[:options] || {}).delete(:rename_from)) next unless from.has_key?(from_table_name) delta[:rename] ||= {} delta[:rename][table_name] = from_table_name from.delete(from_table_name) to.delete(table_name) end end to.each do |table_name, to_attrs| next unless target?(table_name) if (from_attrs = from.delete(table_name)) scan_change(table_name, from_attrs, to_attrs, delta) else delta[:add] ||= {} delta[:add][table_name] = to_attrs end end unless @options[:merge] from.each do |table_name, from_attrs| next unless target?(table_name) delta[:delete] ||= {} delta[:delete][table_name] = from_attrs end end Ridgepole::Delta.new(delta, @options) end private def scan_change(table_name, from, to, delta) from = (from || {}).dup to = (to || {}).dup table_delta = {} scan_options_change(from[:options], to[:options], table_delta) scan_definition_change(from[:definition], to[:definition], table_delta) scan_indices_change(from[:indices], to[:indices], table_delta) unless table_delta.empty? delta[:change] ||= {} delta[:change][table_name] = table_delta end end def scan_options_change(from, to, table_delta) # XXX: Warn differences of options end def scan_definition_change(from, to, table_delta) from = (from || {}).dup to = (to || {}).dup definition_delta = {} to.dup.each do |column_name, to_attrs| if (from_column_name = (to_attrs[:options] || {}).delete(:rename_from)) next unless from.has_key?(from_column_name) definition_delta[:rename] ||= {} definition_delta[:rename][column_name] = from_column_name from.delete(from_column_name) to.delete(column_name) end end priv_column_name = nil to.each do |column_name, to_attrs| if (from_attrs = from.delete(column_name)) normalize_column_options!(from_attrs[:options]) normalize_column_options!(to_attrs[:options]) if from_attrs != to_attrs definition_delta[:change] ||= {} definition_delta[:change][column_name] = to_attrs end else definition_delta[:add] ||= {} to_attrs[:options] ||= {} unless @options[:merge] if priv_column_name to_attrs[:options][:after] = priv_column_name else to_attrs[:options][:first] = true end end definition_delta[:add][column_name] = to_attrs end priv_column_name = column_name end unless @options[:merge] from.each do |column_name, from_attrs| definition_delta[:delete] ||= {} definition_delta[:delete][column_name] = from_attrs end end unless definition_delta.empty? table_delta[:definition] = definition_delta end end def scan_indices_change(from, to, table_delta) from = (from || {}).dup to = (to || {}).dup indices_delta = {} to.each do |index_name, to_attrs| if (from_attrs = from.delete(index_name)) if from_attrs != to_attrs indices_delta[:add] ||= {} indices_delta[:add][index_name] = to_attrs unless @options[:merge] indices_delta[:delete] ||= {} indices_delta[:delete][index_name] = from_attrs end end else indices_delta[:add] ||= {} indices_delta[:add][index_name] = to_attrs end end unless @options[:merge] from.each do |index_name, from_attrs| indices_delta[:delete] ||= {} indices_delta[:delete][index_name] = from_attrs end end unless indices_delta.empty? table_delta[:indices] = indices_delta end end def target?(table_name) not @options[:tables] or @options[:tables].include?(table_name) end def normalize_column_options!(opts) opts[:null] = true unless opts.has_key?(:null) unless @options[:disable_mysql_unsigned] opts[:unsigned] = false unless opts.has_key?(:unsigned) end end end