lib/loaders/csv_loader.rb in datashift-0.15.0 vs lib/loaders/csv_loader.rb in datashift-0.16.0

- old
+ new

@@ -9,13 +9,13 @@ require 'loaders/loader_base' require 'datashift/exceptions' require 'datashift/method_mapper' module DataShift - + module CsvLoading - + include DataShift::Logging # Load data through active Record models into DB from a CSV file # # Assumes header_row is first row i.e row 0 @@ -29,13 +29,13 @@ # # [:mandatory] : Array of mandatory column names # [:force_inclusion] : Array of inbound column names to force into mapping # [:include_all] : Include all headers in processing - takes precedence of :force_inclusion # [:strict] : Raise exception when no mapping found for a column heading (non mandatory) - + def perform_csv_load(file_name, options = {}) - + require "csv" # TODO - can we abstract out what a 'parsed file' is - so a common object can represent excel,csv etc # then we can make load() more generic @@ -46,23 +46,25 @@ populate_method_mapper_from_headers( @parsed_file.shift, options) puts "\n\n\nLoading from CSV file: #{file_name}" puts "Processing #{@parsed_file.size} rows" begin - + load_object_class.transaction do @reporter.reset @parsed_file.each_with_index do |row, i| - - @current_row = row - + + @current_row = row + @reporter.processed_object_count += 1 - + + logger.info("Begin processing Row #{@reporter.processed_object_count} from CSV file") + begin # First assign any default values for columns not included in parsed_file - process_missing_columns_with_defaults + process_defaults # TODO - Smart sorting of column processing order .... # Does not currently ensure mandatory columns (for valid?) processed first but model needs saving # before associations can be processed so user should ensure mandatory columns are prior to associations @@ -71,75 +73,75 @@ # Iterate over the columns method_mapper found in Excel, # pulling data out of associated column @method_mapper.method_details.each_with_index do |method_detail, col| + unless method_detail + logger.warn("No method_detail found for col #{col + 1} #{method_detail}") + next # TODO populate unmapped with a real MethodDetail that is 'null' and create is_nil + end + value = row[col] - prepare_data(method_detail, value) - - process() + process(method_detail, value) end rescue => e - failure( row, true ) - logger.error "Failed to process row [#{i}] (#{@current_row})" - + failure(row, true) + logger.error e.inspect + logger.error e.backtrace.first.inspect + logger.error "Failed to process row [#{@reporter.processed_object_count}] (#{@current_row})" + if(verbose) - puts "Failed to process row [#{i}] (#{@current_row})" - puts e.inspect + puts "Failed to process row [#{@reporter.processed_object_count}] (#{@current_row})" + puts e.inspect end - + # don't forget to reset the load object new_load_object next end - - # TODO - make optional - all or nothing or carry on and dump out the exception list at end - unless(save) - failure - logger.error "Failed to save row [#{@current_row}] (#{load_object.inspect})" - logger.error load_object.errors.inspect if(load_object) - else - logger.info "Row #{@current_row} succesfully SAVED : ID #{load_object.id}" - @reporter.add_loaded_object(@load_object) - end + # TODO - make optional - all or nothing or carry on and dump out the exception list at end + + logger.debug "Attempting Save on : #{load_object.inspect}" + + save_and_report + # don't forget to reset the object or we'll update rather than create new_load_object - end - + raise ActiveRecord::Rollback if(options[:dummy]) # Don't actually create/upload to DB if we are doing dummy run end rescue => e - puts "CAUGHT ", e.backtrace, e.inspect + logger.error "perform_csv_load failed - #{e.message}:\n#{e.backtrace}" if e.is_a?(ActiveRecord::Rollback) && options[:dummy] - puts "CSV loading stage complete - Dummy run so Rolling Back." + logger.info "CSV loading stage complete - Dummy run so Rolling Back." else raise e end ensure report - end - + end # transaction + end end - + class CsvLoader < LoaderBase include DataShift::CsvLoading - def initialize(klass, find_operators = true, object = nil, options = {}) - super( klass, find_operators, object, options ) + def initialize(klass, object = nil, options = {}) + super( klass, object, options ) raise "Cannot load - failed to create a #{klass}" unless @load_object end def perform_load( file_name, options = {} ) perform_csv_load( file_name, options ) puts "CSV loading stage complete - #{loaded_count} rows added." end end - + end \ No newline at end of file