if RUBY_VERSION >= "1.9" require 'csv' else require 'fastercsv' ::CSV = ::FasterCSV end module Amalgalite ## # A class to deal with importing CSV data into a single table in the # database. # class CSVTableImporter def initialize( csv_path, database, table_name, options = {} ) @csv_path = File.expand_path( csv_path ) @database = database @table_name = table_name @table = @database.schema.tables[@table_name] @options = options validate end def run @database.transaction do |db| db.prepare( insert_sql ) do |stmt| ::CSV.foreach( @csv_path, **@options ) do |row| stmt.execute( row ) end end end end ## # The column names of the import table in definiation order # def column_names @table.columns_in_order.collect { |c| c.name } end ## # The columns used for the insertion. This is either #column_names # or the value out of @options[:headers] if that value is an Array # def insert_column_list column_list = self.column_names if Array === @options[:headers] then column_list = @options[:headers] end return column_list end ## # The prepared statement SQL that is used for the import # def insert_sql column_sql = insert_column_list.join(",") vars = insert_column_list.collect { |x| "?" }.join(",") return "INSERT INTO #{@table_name}(#{column_sql}) VALUES (#{vars})" end def table_list @database.schema.tables.keys end ## # validate that the arguments for initialization are valid and that the #run # method will probably execute # def validate raise ArgumentError, "CSV file #{@csv_path} does not exist" unless File.exist?( @csv_path ) raise ArgumentError, "CSV file #{@csv_path} is not readable" unless File.readable?( @csv_path ) raise ArgumentError, "The table '#{@table_name} is not found in the database. The known tables are #{table_list.sort.join(", ")}" unless @table end end end