class Miguel::Migrator

Class for generating database migration from one schema to another.

Public Instance Methods

change_migration( from, to, out = Dumper.new ) click to toggle source

Generate one way Sequel migration.

# File lib/miguel/migrator.rb, line 221
def change_migration( from, to, out = Dumper.new )
  out.dump "Sequel.migration" do
    out.dump "change" do
      changes( from, to, out )
    end
  end
end
changes( from, to, out = Dumper.new ) click to toggle source

Generate code for changing one schema to another.

# File lib/miguel/migrator.rb, line 194
def changes( from, to, out = Dumper.new )
  from_keys = prepare_keys( from.tables )
  to_keys = prepare_keys( to.tables )

  old_keys, same_keys, new_keys = separate( from_keys, to_keys )

  from_names = from.table_names
  to_names = to.table_names

  old_names, same_names, new_names = separate( from_names, to_names )

  old_tables = from.named_tables( old_names )
  new_tables = to.named_tables( new_names )

  from_tables = from.named_tables( same_names )
  to_tables = to.named_tables( same_names )

  dump_drop_foreign_keys( out, old_keys )
  dump_drop_tables( out, old_tables )
  dump_alter_tables( out, from_tables, to_tables )
  dump_add_tables( out, new_tables )
  dump_add_foreign_keys( out, new_keys )

  out
end
full_migration( from, to, out = Dumper.new ) click to toggle source

Generate both ways Sequel migration.

# File lib/miguel/migrator.rb, line 230
def full_migration( from, to, out = Dumper.new )
  out.dump "Sequel.migration" do
    out.dump "up" do
      changes( from, to, out )
    end
    out.dump "down" do
      changes( to, from, out )
    end
  end
end
Also aliased as: migration
migration( from, to, out = Dumper.new )
Alias for: full_migration

Private Instance Methods

dump_add_columns( out, columns ) click to toggle source

Generate code for adding given columns.

# File lib/miguel/migrator.rb, line 123
def dump_add_columns( out, columns )
  for column in columns
    if column.type == :primary_key
      out << "add_primary_key #{column.out_name}#{column.out_opts}"
    else
      out << "add_column #{column.out_name}, #{column.out_type}#{column.out_default_opts}"
    end
  end
end
dump_add_foreign_keys( out, table_keys ) click to toggle source

Generate code for adding given foreign keys.

# File lib/miguel/migrator.rb, line 62
def dump_add_foreign_keys( out, table_keys )
  dump_foreign_keys( out, table_keys ) do |key|
    out << "add_foreign_key #{key.out_columns}, #{key.out_table_name}#{key.out_canonic_opts}"
  end
end
dump_add_indexes( out, indexes ) click to toggle source

Generate code for adding given indexes.

# File lib/miguel/migrator.rb, line 105
def dump_add_indexes( out, indexes )
  for index in indexes
    out << "add_index #{index.out_columns}#{index.out_canonic_opts}"
  end
end
dump_add_tables( out, tables ) click to toggle source

Generate code for adding given tables.

# File lib/miguel/migrator.rb, line 76
def dump_add_tables( out, tables )
  for table in tables
    out.dump "create_table #{table.out_name}" do
      for column in table.columns
        column.dump( out )
      end
      for index in table.indexes
        index.dump( out )
      end
      # No foreign keys here - those are added in a separate pass later.
    end
  end
end
dump_alter_column( out, from, to ) click to toggle source

Generate code for altering given column.

# File lib/miguel/migrator.rb, line 134
def dump_alter_column( out, from, to )
  if from.allow_null != to.allow_null && to.allow_null
    out << "set_column_allow_null #{to.out_name}"
  end
  if from.canonic_type != to.canonic_type || from.type_opts != to.type_opts
    out << "set_column_type #{to.out_name}, #{to.out_type}#{to.out_opts}"
  end
  if from.default != to.default
    out << "set_column_default #{to.out_name}, #{to.out_default}"
  end
  if from.allow_null != to.allow_null && ! to.allow_null
    out << "set_column_not_null #{to.out_name}"
  end
end
dump_alter_columns( out, from_columns, to_columns ) click to toggle source

Generate code for altering given columns.

# File lib/miguel/migrator.rb, line 150
def dump_alter_columns( out, from_columns, to_columns )
  each_pair( :column, from_columns, to_columns ) do |from, to|
    dump_alter_column( out, from, to )
  end
end
dump_alter_table( out, from, to ) click to toggle source

Generate code for altering given table.

# File lib/miguel/migrator.rb, line 157
def dump_alter_table( out, from, to )
  old_indexes, same_indexes, new_indexes = separate( from.indexes, to.indexes )

  from_names = from.column_names
  to_names = to.column_names

  old_names, same_names, new_names = separate( from_names, to_names )

  old_columns = from.named_columns( old_names )
  new_columns = to.named_columns( new_names )

  from_columns = from.named_columns( same_names )
  to_columns = to.named_columns( same_names )

  from_columns, same_columns, to_columns = separate( from_columns, to_columns )

  return if [ old_indexes, new_indexes, old_columns, new_columns, to_columns ].all?{ |x| x.empty? }

  out.dump "alter_table #{to.out_name}" do
    dump_drop_indexes( out, old_indexes )
    dump_drop_columns( out, old_columns )
    dump_alter_columns( out, from_columns, to_columns )
    dump_add_columns( out, new_columns )
    dump_add_indexes( out, new_indexes )
  end
end
dump_alter_tables( out, from_tables, to_tables ) click to toggle source

Generate code for altering given tables.

# File lib/miguel/migrator.rb, line 185
def dump_alter_tables( out, from_tables, to_tables )
  each_pair( :table, from_tables, to_tables ) do |from, to|
    dump_alter_table( out, from, to )
  end
end
dump_drop_columns( out, columns ) click to toggle source

Generate code for dropping given columns.

# File lib/miguel/migrator.rb, line 112
def dump_drop_columns( out, columns )
  for column in columns
    if column.primary_key_constraint?
      out << "drop_constraint #{column.out_name}, :type => :primary_key#{column.out_opts(' # ')}"
    else
      out << "drop_column #{column.out_name} # #{column.out_type}#{column.out_opts}"
    end
  end
end
dump_drop_foreign_keys( out, table_keys ) click to toggle source

Generate code for dropping given foreign keys.

# File lib/miguel/migrator.rb, line 69
def dump_drop_foreign_keys( out, table_keys )
  dump_foreign_keys( out, table_keys ) do |key|
    out << "drop_foreign_key #{key.out_columns} # #{key.out_table_name}#{key.out_canonic_opts}"
  end
end
dump_drop_indexes( out, indexes ) click to toggle source

Generate code for dropping given indexes.

# File lib/miguel/migrator.rb, line 98
def dump_drop_indexes( out, indexes )
  for index in indexes
    out << "drop_index #{index.out_columns}#{index.out_canonic_opts(' # ')}"
  end
end
dump_drop_tables( out, tables ) click to toggle source

Generate code for dropping given tables.

# File lib/miguel/migrator.rb, line 91
def dump_drop_tables( out, tables )
  for table in tables
    out << "drop_table #{table.out_name}"
  end
end
dump_foreign_keys( out, table_keys, &block ) click to toggle source

Generate code for altering given foreign keys.

# File lib/miguel/migrator.rb, line 53
def dump_foreign_keys( out, table_keys, &block )
  for name, keys in split_keys( table_keys )
    out.dump "alter_table #{name.inspect}" do
      keys.each &block
    end
  end
end
each_pair( name, from_items, to_items ) { |from, to| ... } click to toggle source

Iterate over matching pairs of named items.

# File lib/miguel/migrator.rb, line 25
def each_pair( name, from_items, to_items )
  for from, to in from_items.zip( to_items )
    fail "invalid #{name} pair #{from.name} -> #{to.name}" unless from.name == to.name
    yield from, to
  end
end
prepare_keys( tables ) click to toggle source

Convert foreign keys from given tables into [ table name, foreign key ] pairs for easier comparison.

# File lib/miguel/migrator.rb, line 33
def prepare_keys( tables )
  result = []
  for table in tables
    for key in table.foreign_keys
      result << [ table.name, key ]
    end
  end
  result
end
separate( before, after ) click to toggle source

Separate items in before and after arrays into old items, same items and new items.

# File lib/miguel/migrator.rb, line 14
def separate( before, after )
  # Note that we have to use ==, so we can't use & and - operators which use eql?.
  same = after.select{ |x| before.find{ |y| x == y } }
  [
    before.reject{ |x| same.find{ |y| x == y } },
    same,
    after.reject{ |x| same.find{ |y| x == y } },
  ]
end
split_keys( table_keys ) click to toggle source

Convert [ table name, foreign key ] pairs into hash of foreign keys per table.

# File lib/miguel/migrator.rb, line 44
def split_keys( table_keys )
  result = {}
  for name, key in table_keys
    ( result[ name ] ||= [] ) << key
  end
  result
end