namespace :db do

[ :migrate, :rollback ].each do |n|
  namespace n do |migration_task|
    original_task = migration_task.scope.path

    [:with_sql, :to_sql ].each do |t|

      desc "Run migration, and generated SQL" if t == :with_sql
      desc "Generate migration SQL" if t == :to_sql
      task t => :environment do |sql_task|

        case original_task
        when "db:migrate"
          filename = 'db/upgrade.sql'
        when "db:rollback"
          filename = 'db/rollback.sql'
        else
          raise "unkown migration type #{original_task}"
        end

        ActiveRecord::Base.connection.class.class_eval do
          # alias the adapter's execute for later use
          alias :old_execute :execute

          SQL_FILENAME = filename
          RUN_SQL = sql_task.name.ends_with?("with_sql")

          # define our own execute
          def execute(sql, name = nil)
            # check for some DDL and DML statements
            if /^(create|alter|drop|insert|delete|update)/i.match sql
              File.open(SQL_FILENAME, 'a') { |f| f.puts "#{sql};\n" }
              old_execute sql, name if RUN_SQL
            else
              # pass everything else to the aliased execute
              old_execute sql, name
            end
          end

        end

        # create or delete content of migration.sql
        File.open(SQL_FILENAME, 'w') { |f| f.puts "-- Script created @ #{Time.now}" }

        # invoke the normal migration procedure now
        Rake::Task[original_task].invoke

        puts "Ran #{original_task} and wrote sql to #{filename}"
      end
    end
  end
end

end