Class: ActiveRecord::SchemaDumper

This class is used to dump the database schema for some connection to some output format (i.e., ActiveRecord::Schema).

Public Class Methods


dump (connection=ActiveRecord::Base.connection, stream=STDOUT)

    # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 16
16:     def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
17:       new(connection).dump(stream)
18:       stream
19:     end

new (connection)

    # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 30
30:       def initialize(connection)
31:         @connection = connection
32:         @types = @connection.native_database_types
33:         @info = @connection.select_one("SELECT * FROM schema_info") rescue nil
34:       end

Public Instance Methods


dump (stream)

    # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 21
21:     def dump(stream)
22:       header(stream)
23:       tables(stream)
24:       trailer(stream)
25:       stream
26:     end

Private Instance Methods


default_string (value)

     # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 151
151:       def default_string(value)
152:         case value
153:         when BigDecimal
154:           value.to_s
155:         when Date, DateTime, Time
156:           "'" + value.to_s(:db) + "'"
157:         else
158:           value.inspect
159:         end
160:       end

header (stream)

    # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 36
36:       def header(stream)
37:         define_params = @info ? ":version => #{@info['version']}" : ""
38: 
39:         stream.puts "# This file is auto-generated from the current state of the database. Instead of editing this file, \n# please use the migrations feature of ActiveRecord to incrementally modify your database, and\n# then regenerate this schema definition.\n#\n# Note that this schema.rb definition is the authoritative source for your database schema. If you need\n# to create the application database on another system, you should be using db:schema:load, not running\n# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations\n# you'll amass, the slower it'll run and the greater likelihood for issues).\n#\n# It's strongly recommended to check this file into your version control system.\n\nActiveRecord::Schema.define(\#{define_params}) do\n\n"
40:       end

indexes (table, stream)

     # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 162
162:       def indexes(table, stream)
163:         indexes = @connection.indexes(table)
164:         indexes.each do |index|
165:           stream.print "  add_index #{index.table.inspect}, #{index.columns.inspect}, :name => #{index.name.inspect}"
166:           stream.print ", :unique => true" if index.unique
167:           stream.puts
168:         end
169:         stream.puts unless indexes.empty?
170:       end

table (table, stream)

     # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 75
 75:       def table(table, stream)
 76:         columns = @connection.columns(table)
 77:         begin
 78:           tbl = StringIO.new
 79: 
 80:           if @connection.respond_to?(:pk_and_sequence_for)
 81:             pk, pk_seq = @connection.pk_and_sequence_for(table)
 82:           end
 83:           pk ||= 'id'
 84: 
 85:           tbl.print "  create_table #{table.inspect}"
 86:           if columns.detect { |c| c.name == pk }
 87:             if pk != 'id'
 88:               tbl.print %Q(, :primary_key => "#{pk}")
 89:             end
 90:           else
 91:             tbl.print ", :id => false"
 92:           end
 93:           tbl.print ", :force => true"
 94:           tbl.puts " do |t|"
 95: 
 96:           column_specs = columns.map do |column|
 97:             raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
 98:             next if column.name == pk
 99:             spec = {}
100:             spec[:name]      = column.name.inspect
101:             spec[:type]      = column.type.to_s
102:             spec[:limit]     = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
103:             spec[:precision] = column.precision.inspect if !column.precision.nil?
104:             spec[:scale]     = column.scale.inspect if !column.scale.nil?
105:             spec[:null]      = 'false' if !column.null
106:             spec[:default]   = default_string(column.default) if !column.default.nil?
107:             (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
108:             spec
109:           end.compact
110: 
111:           # find all migration keys used in this table
112:           keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map(&:keys).flatten
113: 
114:           # figure out the lengths for each column based on above keys
115:           lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
116: 
117:           # the string we're going to sprintf our values against, with standardized column widths
118:           format_string = lengths.map{ |len| "%-#{len}s" }
119: 
120:           # find the max length for the 'type' column, which is special
121:           type_length = column_specs.map{ |column| column[:type].length }.max
122: 
123:           # add column type definition to our format string
124:           format_string.unshift "    t.%-#{type_length}s "
125: 
126:           format_string *= ''
127: 
128:           column_specs.each do |colspec|
129:             values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
130:             values.unshift colspec[:type]
131:             tbl.print((format_string % values).gsub(/,\s*$/, ''))
132:             tbl.puts
133:           end
134: 
135:           tbl.puts "  end"
136:           tbl.puts
137:           
138:           indexes(table, tbl)
139: 
140:           tbl.rewind
141:           stream.print tbl.read
142:         rescue => e
143:           stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
144:           stream.puts "#   #{e.message}"
145:           stream.puts
146:         end
147:         
148:         stream
149:       end

tables (stream)

    # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 61
61:       def tables(stream)
62:         @connection.tables.sort.each do |tbl|
63:           next if ["schema_info", ignore_tables].flatten.any? do |ignored|
64:             case ignored
65:             when String; tbl == ignored
66:             when Regexp; tbl =~ ignored
67:             else
68:               raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
69:             end
70:           end 
71:           table(tbl, stream)
72:         end
73:       end

trailer (stream)

    # File vendor/rails/activerecord/lib/active_record/schema_dumper.rb, line 57
57:       def trailer(stream)
58:         stream.puts "end"
59:       end