SQL data streaming

If you ever need to provide a download stream based on data from Postgres SQL, there’s a great low level/optimized example on how to do it with Rails.

For my needs, I adapted it to work with ActionController::Live and send_stream. This example streams xlsx with xlsxtream, but can be repurposed for any generated data:

config/initializers/mime_types.rb

Mime::Type.register \
  'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  :xlsx

app/controllers/concerns/sql_streaming.rb

module SqlStreaming
  def sql_stream(sql)
    raw_connection = ApplicationRecord.connection.raw_connection
    raw_connection.send_query(sql)
    raw_connection.set_single_row_mode
    raw_connection.get_result.stream_each do |record|
      yield record
    end
    raw_connection.get_result
  end
end

in the controller

include SqlStreaming


def index
  sql = Model.all.to_sql

  send_stream(filename: "file.xlsx") do |stream|
    xlsx = Xlsxtream::Workbook.new(stream)
    headings_written = false
  
    xlsx.write_worksheet(name: sheet_name, auto_format: true) do |sheet|
      sql_stream(sql) do |record|
        unless headings_written
          sheet.add_row headings
          headings_written = true
        end
  
        sheet.add_row make_row(record)
      end
    end
  
    xlsx.close
  end
end

Code snippets in this post are covered by 0BSD License.



Date
November 6, 2024