hensei-api/lib/granblue/importers/base_importer.rb
Justin Edmund 901a7398fa Updates only require values that will change
When updating a row, fields that don't have a provided value will not be changed
2025-01-12 19:03:25 -08:00

139 lines
3.9 KiB
Ruby

# frozen_string_literal: true
module Granblue
module Importers
class BaseImporter
attr_reader :new_records, :updated_records
def initialize(file_path, test_mode: false, verbose: false, logger: nil)
@file_path = file_path
@test_mode = test_mode
@verbose = verbose
@logger = logger
@new_records = Hash.new { |h, k| h[k] = [] }
@updated_records = Hash.new { |h, k| h[k] = [] }
end
def import
CSV.foreach(@file_path, headers: true) do |row|
import_row(row)
end
{ new: @new_records, updated: @updated_records }
end
private
def import_row(row)
attributes = build_attributes(row)
# Remove nil values from attributes hash for updates
# Keep them for new records to ensure proper defaults
record = find_or_create_record(attributes)
track_record(record) if record
end
def find_or_create_record(attributes)
existing_record = model_class.find_by(granblue_id: attributes[:granblue_id])
if existing_record
if @test_mode
log_test_update(existing_record, attributes)
nil
else
# For updates, only include non-nil attributes
update_attributes = attributes.compact
was_updated = update_attributes.any? { |key, value| existing_record[key] != value }
existing_record.update!(update_attributes) if was_updated
[existing_record, was_updated]
end
else
if @test_mode
log_test_creation(attributes)
nil
else
# For new records, use all attributes including nil values
[model_class.create!(attributes), false]
end
end
end
def track_record(result)
record, was_updated = result
type = model_class.name.demodulize.downcase
if was_updated
@updated_records[type] << record.granblue_id
log_updated_record(record) if @verbose
else
@new_records[type] << record.granblue_id
log_new_record(record) if @verbose
end
end
def log_test_update(record, attributes)
# For test mode, show only the attributes that would be updated
update_attributes = attributes.compact
@logger&.send(:log_operation, "Update #{model_class.name} #{record.granblue_id}: #{update_attributes.inspect}")
end
def log_test_creation(attributes)
@logger&.send(:log_operation, "Create #{model_class.name}: #{attributes.inspect}")
end
def log_new_record(record)
puts "Created #{model_class.name} with ID: #{record.granblue_id}"
end
def log_updated_record(record)
puts "Updated #{model_class.name} with ID: #{record.granblue_id}"
end
def parse_value(value)
return nil if value.nil? || value.strip.empty?
value
end
def parse_integer(value)
return nil if value.nil? || value.strip.empty?
value.to_i
end
def parse_float(value)
return nil if value.nil? || value.strip.empty?
value.to_f
end
def parse_boolean(value)
return nil if value.nil? || value.strip.empty?
value == 'true'
end
def parse_date(date_str)
return nil if date_str.nil? || date_str.strip.empty?
Date.parse(date_str) rescue nil
end
def parse_array(array_str)
return [] if array_str.nil? || array_str.strip.empty?
array_str.tr('{}', '').split(',')
end
def parse_integer_array(array_str)
parse_array(array_str).map(&:to_i)
end
def model_class
raise NotImplementedError, 'Subclasses must define model_class'
end
def build_attributes(row)
raise NotImplementedError, 'Subclasses must define build_attributes'
end
end
end
end