|
|
|
require 'csv'
|
|
|
|
|
|
|
|
class BikeCsvImporter
|
|
|
|
|
|
|
|
include BikeCsvImporter::Cache
|
|
|
|
include BikeCsvImporter::Cleaner
|
|
|
|
include BikeCsvImporter::BikeAttrs
|
|
|
|
include BikeCsvImporter::Logs
|
|
|
|
|
|
|
|
attr_reader :file
|
|
|
|
|
|
|
|
def initialize(file)
|
|
|
|
@file = file
|
|
|
|
end
|
|
|
|
|
|
|
|
def run(dry_run)
|
|
|
|
imported_count, skipped_count = 0, 0
|
|
|
|
|
|
|
|
puts "Performing a #{dry_run ? 'DRY RUN' : 'LIVE RUN'} of import"
|
|
|
|
|
|
|
|
fetch do |bike_hash|
|
|
|
|
bike = new_bike bike_hash
|
|
|
|
check_method = dry_run ? :valid? : :save
|
|
|
|
if bike.try check_method
|
|
|
|
puts "Imported #{bike.shop_id}: #{bike}".green
|
|
|
|
|
|
|
|
logs = new_logs_entries bike, bike_hash
|
|
|
|
logs.each do |log|
|
|
|
|
if log.send check_method
|
|
|
|
puts "\tLog entry created: #{log.inspect}".green
|
|
|
|
else
|
|
|
|
puts "\tLog entry creation failed: #{log.errors.full_messages.join '; '}".red
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
imported_count += 1
|
|
|
|
else
|
|
|
|
puts "Skipped #{bike.try(:shop_id) || bike_hash.values.first}: #{bike.try(:errors).try(:full_messages).try :join, '; '}".red
|
|
|
|
skipped_count += 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
puts "#{imported_count} bikes imported, #{skipped_count} bikes skipped, total of #{imported_count + skipped_count} rows in the CSV"
|
|
|
|
end
|
|
|
|
|
|
|
|
def analyze(fields = [])
|
|
|
|
puts "Analyzing CSV values frequency for #{fields.any? ? fields.join(', ') + ' field' : 'all fields'}"
|
|
|
|
|
|
|
|
fields = fields.map &:downcase
|
|
|
|
grouped = {}
|
|
|
|
fetch do |bike_hash|
|
|
|
|
bike_hash.each do |key, value|
|
|
|
|
next if fields.any? && !fields.include?(key)
|
|
|
|
grouped[key] ||= {}
|
|
|
|
grouped[key][value] ||= 0
|
|
|
|
grouped[key][value] += 1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
grouped.each do |field, values|
|
|
|
|
puts "#{field}:"
|
|
|
|
values.each do |value, count|
|
|
|
|
puts "\t#{value.inspect}: #{count}"
|
|
|
|
end
|
|
|
|
puts "\tTotal of #{values.count} distinct values"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def fetch
|
|
|
|
CSV.foreach(file).each_with_index do |row, i|
|
|
|
|
if i.zero?
|
|
|
|
parse_header row
|
|
|
|
else
|
|
|
|
yield parse_bike(row)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse_header(row)
|
|
|
|
@header = row.map(&:downcase)
|
|
|
|
end
|
|
|
|
|
|
|
|
def parse_bike(row)
|
|
|
|
@header.zip(row).to_h
|
|
|
|
end
|
|
|
|
|
|
|
|
def new_bike(bike_hash)
|
|
|
|
Bike.new bike_attrs(bike_hash)
|
|
|
|
end
|
|
|
|
|
|
|
|
def new_logs_entries(bike, bike_hash)
|
|
|
|
%i{ acquired comment gone }.map { |x| send :"log_entry_#{x}", bike, bike_hash }.compact
|
|
|
|
end
|
|
|
|
end
|