mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 09:41:40 -05:00
146 lines
3.6 KiB
Ruby
146 lines
3.6 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Users::ImportData::Stats
|
|
BATCH_SIZE = 1000
|
|
|
|
def initialize(user, stats_data)
|
|
@user = user
|
|
@stats_data = stats_data
|
|
end
|
|
|
|
def call
|
|
return 0 unless stats_data.is_a?(Array)
|
|
|
|
Rails.logger.info "Importing #{stats_data.size} stats for user: #{user.email}"
|
|
|
|
valid_stats = filter_and_prepare_stats
|
|
|
|
if valid_stats.empty?
|
|
Rails.logger.info "Stats import completed. Created: 0"
|
|
return 0
|
|
end
|
|
|
|
deduplicated_stats = filter_existing_stats(valid_stats)
|
|
|
|
if deduplicated_stats.size < valid_stats.size
|
|
Rails.logger.debug "Skipped #{valid_stats.size - deduplicated_stats.size} duplicate stats"
|
|
end
|
|
|
|
total_created = bulk_import_stats(deduplicated_stats)
|
|
|
|
Rails.logger.info "Stats import completed. Created: #{total_created}"
|
|
total_created
|
|
end
|
|
|
|
private
|
|
|
|
attr_reader :user, :stats_data
|
|
|
|
def filter_and_prepare_stats
|
|
valid_stats = []
|
|
skipped_count = 0
|
|
|
|
stats_data.each do |stat_data|
|
|
next unless stat_data.is_a?(Hash)
|
|
|
|
unless valid_stat_data?(stat_data)
|
|
skipped_count += 1
|
|
next
|
|
end
|
|
|
|
prepared_attributes = prepare_stat_attributes(stat_data)
|
|
valid_stats << prepared_attributes if prepared_attributes
|
|
end
|
|
|
|
if skipped_count > 0
|
|
Rails.logger.warn "Skipped #{skipped_count} stats with invalid or missing required data"
|
|
end
|
|
|
|
valid_stats
|
|
end
|
|
|
|
def prepare_stat_attributes(stat_data)
|
|
attributes = stat_data.except('created_at', 'updated_at', 'sharing_uuid')
|
|
|
|
attributes['user_id'] = user.id
|
|
attributes['created_at'] = Time.current
|
|
attributes['updated_at'] = Time.current
|
|
attributes['sharing_uuid'] = SecureRandom.uuid
|
|
|
|
attributes.symbolize_keys
|
|
rescue StandardError => e
|
|
ExceptionReporter.call(e, 'Failed to prepare stat attributes')
|
|
|
|
nil
|
|
end
|
|
|
|
def filter_existing_stats(stats)
|
|
return stats if stats.empty?
|
|
|
|
existing_stats_lookup = {}
|
|
user.stats.select(:year, :month).each do |stat|
|
|
key = [stat.year, stat.month]
|
|
existing_stats_lookup[key] = true
|
|
end
|
|
|
|
filtered_stats = stats.reject do |stat|
|
|
key = [stat[:year], stat[:month]]
|
|
if existing_stats_lookup[key]
|
|
Rails.logger.debug "Stat already exists: #{stat[:year]}-#{stat[:month]}"
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
filtered_stats
|
|
end
|
|
|
|
def bulk_import_stats(stats)
|
|
total_created = 0
|
|
|
|
stats.each_slice(BATCH_SIZE) do |batch|
|
|
begin
|
|
result = Stat.upsert_all(
|
|
batch,
|
|
returning: %w[id],
|
|
on_duplicate: :skip
|
|
)
|
|
|
|
batch_created = result.count
|
|
total_created += batch_created
|
|
|
|
Rails.logger.debug "Processed batch of #{batch.size} stats, created #{batch_created}, total created: #{total_created}"
|
|
|
|
rescue StandardError => e
|
|
ExceptionReporter.call(e, 'Failed to process stat batch')
|
|
end
|
|
end
|
|
|
|
total_created
|
|
end
|
|
|
|
def valid_stat_data?(stat_data)
|
|
return false unless stat_data.is_a?(Hash)
|
|
|
|
unless stat_data['year'].present?
|
|
Rails.logger.error "Failed to create stat: Validation failed: Year can't be blank"
|
|
return false
|
|
end
|
|
|
|
unless stat_data['month'].present?
|
|
Rails.logger.error "Failed to create stat: Validation failed: Month can't be blank"
|
|
return false
|
|
end
|
|
|
|
unless stat_data['distance'].present?
|
|
Rails.logger.error "Failed to create stat: Validation failed: Distance can't be blank"
|
|
return false
|
|
end
|
|
|
|
true
|
|
rescue StandardError => e
|
|
Rails.logger.debug "Stat validation failed: #{e.message} for data: #{stat_data.inspect}"
|
|
false
|
|
end
|
|
end
|