class Convergence::Diff
Constants
- CASE_SENSITIVE_COLUMNS
- CASE_SENSITIVE_TABLE_OPTIONS
Public Instance Methods
diff(from_database, to_database)
click to toggle source
# File lib/convergence/diff.rb, line 7 def diff(from_database, to_database) delta = {} from_database = {} if from_database.nil? delta[:add_table] = scan_add_table(from_database, to_database) delta[:remove_table] = scan_remove_table(from_database, to_database) change_table = scan_change_table(from_database, to_database) delta[:change_table] = change_table[:change] delta[:remove_table].merge!(change_table[:remove]) delta[:add_table].merge!(change_table[:add]) delta end
diff_table(from_table, to_table)
click to toggle source
# File lib/convergence/diff.rb, line 19 def diff_table(from_table, to_table) from = from_table.dup to = to_table.dup delta = {} delta[:remove_column] = scan_remove_column(from, to) return delta if removed_all_columns?(from, delta) delta[:add_column] = scan_add_column(from, to) delta[:change_column] = scan_change_column(from, to) scan_change_order_column(from, to, delta) delta[:remove_index] = scan_change_index(to, from) delta[:add_index] = scan_change_index(from, to) delta[:remove_foreign_key] = scan_change_foreign_key(to, from) delta[:add_foreign_key] = scan_change_foreign_key(from, to) delta[:change_table_option] = scan_change_table_option(from, to) delta end
Private Instance Methods
case_sensitive_column?(column)
click to toggle source
# File lib/convergence/diff.rb, line 173 def case_sensitive_column?(column) CASE_SENSITIVE_COLUMNS.include?(column) end
case_sensitive_table_option?(option)
click to toggle source
# File lib/convergence/diff.rb, line 169 def case_sensitive_table_option?(option) CASE_SENSITIVE_TABLE_OPTIONS.include?(option) end
remove_auto_increment_option?(from_value, to_value)
click to toggle source
# File lib/convergence/diff.rb, line 177 def remove_auto_increment_option?(from_value, to_value) return true if from_value.nil? || to_value.nil? from_value >= to_value end
removed_all_columns?(from_table, diff)
click to toggle source
# File lib/convergence/diff.rb, line 165 def removed_all_columns?(from_table, diff) from_table.columns.each_key.all? { |name| diff[:remove_column].each_key.include?(name) } end
scan_add_column(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 65 def scan_add_column(from, to) to.columns.reject { |column_name, _| from.columns.keys.include?(column_name) } end
scan_add_table(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 38 def scan_add_table(from, to) to.reject { |table_name, _| from.map { |k, _| k }.include?(table_name) } end
scan_change_column(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 73 def scan_change_column(from, to) change_columns = from .columns .map do |column_name, from_column| to_column = to.columns[column_name] if to_column to_column_option_with_type = (from_column.options.map { |k, _v| { k => nil } }.reduce { |a, e| a.merge(e) } || {}) .merge(to_column.options) .merge(type: to_column.type) .map { |k, v| [k, case_sensitive_column?(k) ? v&.to_s : v&.to_s&.downcase] } .to_a from_column_option_with_type = from_column .options .merge(type: from_column.type) .map { |k, v| [k, case_sensitive_column?(k) ? v&.to_s : v&.to_s&.downcase] } .to_a { column_name => Hash[(to_column_option_with_type - from_column_option_with_type)] } end end change_columns .compact .reduce({}) { |a, e| a.merge(e) } .reject { |_k, v| v.empty? } end
scan_change_foreign_key(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 132 def scan_change_foreign_key(from, to) delta = {} to.foreign_keys.each do |name, fk| candidate_foreign_keys = from.foreign_keys.find { |from_name, _| from_name == name } target_fk = candidate_foreign_keys[1] rescue nil if candidate_foreign_keys.nil? delta[name] = fk elsif !target_fk.nil? if target_fk.from_columns != fk.from_columns || target_fk.key_name != fk.key_name || target_fk.options != fk.options || target_fk.to_columns != fk.to_columns || target_fk.to_table != fk.to_table delta[name] = fk end end end delta end
scan_change_index(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 121 def scan_change_index(from, to) delta = {} to.indexes.each do |name, index| candidate_index = from.indexes.find { |from_name, _| from_name == name } if candidate_index.nil? || candidate_index[1].options != index.options delta[name] = index end end delta end
scan_change_order_column(from, to, delta)
click to toggle source
# File lib/convergence/diff.rb, line 98 def scan_change_order_column(from, to, delta) from_columns = from.columns.keys to_columns = to.columns.keys order_changed_columns = Diff::LCS.diff(from_columns, to_columns) .flatten(1) .select(&:adding?) .map(&:element) order_changed_columns.each do |column| before_column_index = to_columns.index { |v| v == column } - 1 before_column = if before_column_index < 0 nil else to_columns[before_column_index] end if delta[:add_column][column] delta[:add_column][column].options.merge!(after: before_column) else delta[:change_column][column] = {} if delta[:change_column][column].nil? delta[:change_column][column].merge!(after: before_column) end end end
scan_change_table(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 46 def scan_change_table(from, to) delta = { change: {}, remove: {}, add: {}} target_tables = from.map { |name, _| name } & to.map { |name, _| name } target_tables.each do |target_table| from_table = from.find { |name, _| name == target_table }[1] to_table = to.find { |name, _| name == target_table }[1] diff = diff_table(from_table, to_table) unless diff.values.all?(&:empty?) if removed_all_columns?(from_table, diff) delta[:remove][target_table] = from_table delta[:add][target_table] = to_table else delta[:change][target_table] = diff end end end delta end
scan_change_table_option(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 152 def scan_change_table_option(from, to) change_options = (from.table_options.map { |k, _v| { k => nil } }.reduce { |a, e| a.merge(e) } || {}) .merge(to.table_options) .reject do |k, v| next false if from.table_options[k].nil? case_sensitive_table_option?(k) ? from.table_options[k].to_s == v.to_s : from.table_options[k].to_s.downcase == v.to_s.downcase end if remove_auto_increment_option?(from.table_options[:auto_increment], to.table_options[:auto_increment]) change_options.delete(:auto_increment) end Hash[change_options] end
scan_remove_column(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 69 def scan_remove_column(from, to) from.columns.reject { |column_name, _| to.columns.keys.include?(column_name) } end
scan_remove_table(from, to)
click to toggle source
# File lib/convergence/diff.rb, line 42 def scan_remove_table(from, to) from.reject { |table_name, _| to.map { |k, _| k }.include?(table_name) } end