module ActiveRecord
  # This class is used to dump the database schema for some connection to some
  # output format (i.e., ActiveRecord::Schema).
  class SchemaDumper #:nodoc:
    private_class_method :new

    def self.dump(connection=ActiveRecord::Base.connection, stream=STDOUT)
      new(connection).dump(stream)
      stream
    end

    def dump(stream)
      header(stream)
      tables(stream)
      trailer(stream)
      stream
    end

    private

      def initialize(connection)
        @connection = connection
        @types = @connection.native_database_types
        @info = @connection.select_one("SELECT * FROM schema_info") rescue nil
      end

      def header(stream)
        define_params = @info ? ":version => #{@info['version']}" : ""

        stream.puts <<HEADER
# This file is autogenerated. Instead of editing this file, please use the
# migrations feature of ActiveRecord to incrementally modify your database, and
# then regenerate this schema definition.

ActiveRecord::Schema.define(#{define_params}) do

HEADER
      end

      def trailer(stream)
        stream.puts "end"
      end

      def tables(stream)
        @connection.tables.sort.each do |tbl|
          next if tbl == "schema_info"
          table(tbl, stream)
        end
      end

      def table(table, stream)
        columns = @connection.columns(table)

        stream.print "  create_table #{table.inspect}"
        stream.print ", :id => false" if !columns.detect { |c| c.name == "id" }
        stream.print ", :force => true"
        stream.puts " do |t|"

        columns.each do |column|
          next if column.name == "id"
          stream.print "    t.column #{column.name.inspect}, #{column.type.inspect}"
          stream.print ", :limit => #{column.limit.inspect}" if column.limit != @types[column.type][:limit] 
          stream.print ", :default => #{column.default.inspect}" if !column.default.nil?
          stream.print ", :null => false" if !column.null
          stream.puts
        end

        stream.puts "  end"
        stream.puts

        indexes(table, stream)
      end

      def indexes(table, stream)
        indexes = @connection.indexes(table)
        indexes.each do |index|
          stream.print "  add_index #{index.table.inspect}, #{index.columns.inspect}, :name => #{index.name.inspect}"
          stream.print ", :unique => true" if index.unique
          stream.puts
        end
        stream.puts unless indexes.empty?
      end
  end
end
