optional_require 'spreadsheet'
module ETL
module Control
# Excel as the final destination.
class ExcelDestination < Destination
# The File to write to
attr_reader :file
# The output order
attr_reader :order
# Flag which indicates to append (default is to overwrite)
attr_accessor :append
# Initialize the object.
# * control: The Control object
# * configuration: The configuration map
# * mapping: The output mapping
#
# Configuration options:
# * :file: The file to write to (REQUIRED)
# * :append: Set to true to append to the file (default is to overwrite)
# * :unique: Set to true to only write unique records
# * :append_rows: Array of rows to append
#
# Mapping options:
# * :order: The order array
def initialize(control, configuration, mapping={})
super
path = Pathname.new(configuration[:file])
@file = path.absolute? ? path : Pathname.new(File.dirname(File.expand_path(control.file))) + path
@append = configuration[:append] ||= false
@unique = configuration[:unique] ? configuration[:unique] + scd_required_fields : configuration[:unique]
@unique.uniq! unless @unique.nil?
@order = mapping[:order] ? mapping[:order] + scd_required_fields : order_from_source
@order.uniq! unless @order.nil?
raise ControlError, "Order required in mapping" unless @order
end
# Close the destination. This will flush the buffer and close the underlying stream or connection.
def close
buffer << append_rows if append_rows
flush
book.write(file)
end
# Flush the destination buffer
def flush
#puts "Flushing buffer (#{file}) with #{buffer.length} rows"
buffer.flatten.each_with_index do |row, index|
#puts "row change type: #{row.change_type}"
# check to see if this row's compound key constraint already exists
# note that the compound key constraint may not utilize virtual fields
next unless row_allowed?(row)
# add any virtual fields
add_virtuals!(row)
# collect all of the values using the order designated in the configuration
values = order.collect do |name|
value = row[name]
case value
when Date, Time, DateTime
value.to_s(:db)
else
value.to_s
end
end
# write the values
sheet.insert_row(index, values)
end
buffer.clear
#puts "After flush there are #{buffer.length} rows"
end
private
# Get the open file excel
def book
@book ||= ( append ? Spreadsheet.open(file) : Spreadsheet::Workbook.new(file) )
end
private
# Get the open sheet
def sheet
@sheet ||= ( append ? book.worksheet(0) : book.create_worksheet() )
end
end
end
end