module ActiveRecord module Tasks # :nodoc: class PostgreSQLDatabaseTasks # :nodoc: DEFAULT_ENCODING = ENV["CHARSET"] || "utf8" ON_ERROR_STOP_1 = "ON_ERROR_STOP=1".freeze delegate :connection, :establish_connection, :clear_active_connections!, to: ActiveRecord::Base def initialize(configuration) @configuration = configuration end def create(master_established = false) establish_master_connection unless master_established connection.create_database configuration["database"], configuration.merge("encoding" => encoding) establish_connection configuration rescue ActiveRecord::StatementInvalid => error if /database .* already exists/ === error.message raise DatabaseAlreadyExists else raise end end def drop establish_master_connection connection.drop_database configuration["database"] end def charset connection.encoding end def collation connection.collation end def purge clear_active_connections! drop create true end def structure_dump(filename) set_psql_env search_path = case ActiveRecord::Base.dump_schemas when :schema_search_path configuration["schema_search_path"] when :all nil when String ActiveRecord::Base.dump_schemas end args = ["-s", "-x", "-O", "-f", filename] unless search_path.blank? args += search_path.split(",").map do |part| "--schema=#{part.strip}" end end args << configuration["database"] run_cmd("pg_dump", args, "dumping") File.open(filename, "a") { |f| f << "SET search_path TO #{connection.schema_search_path};\n\n" } end def structure_load(filename) set_psql_env args = [ "-v", ON_ERROR_STOP_1, "-q", "-f", filename, configuration["database"] ] run_cmd("psql", args, "loading" ) end private def configuration @configuration end def encoding configuration["encoding"] || DEFAULT_ENCODING end def establish_master_connection establish_connection configuration.merge( "database" => "postgres", "schema_search_path" => "public" ) end def set_psql_env ENV["PGHOST"] = configuration["host"] if configuration["host"] ENV["PGPORT"] = configuration["port"].to_s if configuration["port"] ENV["PGPASSWORD"] = configuration["password"].to_s if configuration["password"] ENV["PGUSER"] = configuration["username"].to_s if configuration["username"] end def run_cmd(cmd, args, action) fail run_cmd_error(cmd, args, action) unless Kernel.system(cmd, *args) end def run_cmd_error(cmd, args, action) msg = "failed to execute:\n" msg << "#{cmd} #{args.join(' ')}\n\n" msg << "Please check the output above for any errors and make sure that `#{cmd}` is installed in your PATH and has proper permissions.\n\n" msg end end end end