Class: Sequel::MigrationBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/sequel/migration_builder.rb

Overview

Generates a Sequel migration to bring a database inline with an abstract schema.

Constant Summary collapse

INDENT_SPACES =
'  '

Instance Method Summary collapse

Constructor Details

#initialize(db, options = {}) ⇒ MigrationBuilder

Creates a migration builder for the given database.



16
17
18
19
20
21
22
23
24
25
26
# File 'lib/sequel/migration_builder.rb', line 16

def initialize(db, options={})
  @db = db
  @db_tables = Schema::DbSchemaParser.for_db(db).parse_db_schema
  @db_table_names = @db.tables
  @indent = 0
  @result = []
  @separate_alter_table_statements = !!options[:separate_alter_table_statements]
  # Columns are only added and dropped, never altered. This helps
  # us support Redshift.
  @immutable_columns = !!options[:immutable_columns]
end

Instance Method Details

#alter_table_statement(table_name, operations) ⇒ Object

Generates an individual alter table statement.



100
101
102
103
104
105
106
# File 'lib/sequel/migration_builder.rb', line 100

def alter_table_statement(table_name, operations)
  add_line "alter_table #{table_name.inspect} do"
  indent do
    operations.compact.each {|op| add_line op }
  end
  add_line "end"
end

#alter_tables(current_table_names, tables) ⇒ Object

Generates any alter table statements for current tables.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/sequel/migration_builder.rb', line 77

def alter_tables(current_table_names, tables)
  each_table(current_table_names, tables) do |table_name, table, last_table|
    hsh = table.dup
    hsh[:columns] = hsh[:columns].map {|c| Schema::DbColumn.build_from_hash(c) }
    operations = Schema::AlterTableOperations.
      build(@db_tables[table_name], hsh, :immutable_columns => @immutable_columns)
    unless operations.empty?
      all_operations = if @separate_alter_table_statements
                         operations.map {|o| [o] }
                       else
                         [operations]
                       end

      all_operations.each_with_index do |o, i|
        alter_table_statement table_name, o
        add_blank_line unless last_table && i + 1 == all_operations.size
      end
    end
  end
end

#create_new_tables(new_table_names, tables) ⇒ Object

Generates any create table statements for new tables.



60
61
62
63
64
65
# File 'lib/sequel/migration_builder.rb', line 60

def create_new_tables(new_table_names, tables)
  each_table(new_table_names, tables) do |table_name, table, last_table|
    create_table_statement table_name, table
    add_blank_line unless last_table
  end
end

#create_table_statement(table_name, table) ⇒ Object

Generates an individual create_table statement.



110
111
112
113
114
115
116
117
118
119
# File 'lib/sequel/migration_builder.rb', line 110

def create_table_statement(table_name, table)
  normalize_primary_key(table)
  add_line "create_table #{table_name.inspect}#{pretty_hash(table[:table_options])} do"
  indent do
    output_columns(table[:columns], table[:primary_key])
    output_indexes(table[:indexes])
    output_primary_key(table)
  end
  add_line "end"
end

#drop_new_tables(new_table_names) ⇒ Object

Generates any drop table statements for new tables.



69
70
71
72
73
# File 'lib/sequel/migration_builder.rb', line 69

def drop_new_tables(new_table_names)
  indent do
    new_table_names.reverse.each {|table_name| add_line "drop_table #{table_name.inspect}" }
  end
end

#generate_migration(tables) ⇒ Object

Generates a string of ruby code to define a sequel migration, based on the differences between the database schema of this MigrationBuilder and the tables passed.



32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/sequel/migration_builder.rb', line 32

def generate_migration(tables)
  return if tables.empty? && @db_tables.empty?
  result.clear

  add_line "Sequel.migration do"
  indent do
    generate_migration_body(tables)
  end
  add_line "end\n"

  result.join("\n")
end

#generate_migration_body(tables) ⇒ Object

Generates the ‘change’ block of the migration.



47
48
49
50
51
52
53
54
55
56
# File 'lib/sequel/migration_builder.rb', line 47

def generate_migration_body(tables)
  current_tables, new_tables = table_names(tables).partition do |table_name| 
    @db_table_names.include?(table_name)
  end

  add_line "change do"
  create_new_tables(new_tables, tables)
  alter_tables(current_tables, tables)
  add_line "end"
end

#normalize_primary_key(table) ⇒ Object



121
122
123
# File 'lib/sequel/migration_builder.rb', line 121

def normalize_primary_key(table)
  table[:primary_key] = [table[:primary_key]] if table[:primary_key].kind_of?(Symbol)
end

#output_columns(columns, primary_key) ⇒ Object



125
126
127
128
129
130
131
132
133
# File 'lib/sequel/migration_builder.rb', line 125

def output_columns(columns, primary_key)
  columns.each do |c| 
    column = Schema::DbColumn.build_from_hash(c)
    if inline_primary_key?(primary_key, column)
      column.single_primary_key = true
    end
    add_line column.define_statement
  end
end

#output_indexes(indexes) ⇒ Object



135
136
137
138
139
140
141
142
# File 'lib/sequel/migration_builder.rb', line 135

def output_indexes(indexes)
  if indexes
    add_blank_line
    Schema::DbIndex.build_from_hash(indexes).each do |idx|
      add_line idx.define_statement
    end
  end
end

#output_primary_key(table) ⇒ Object



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/sequel/migration_builder.rb', line 144

def output_primary_key(table)
  primary_key = table[:primary_key]
  primary_key_already_output = table[:columns].any? do |c| 
    inline_primary_key?(primary_key, Schema::DbColumn.build_from_hash(c))
  end

  if primary_key && ! primary_key_already_output
    add_blank_line
    add_line "primary_key #{primary_key.inspect}"
  end
end