dawarich/app/services/users/import_data/trips.rb
2025-06-30 23:54:45 +02:00

169 lines
4.1 KiB
Ruby

# frozen_string_literal: true
class Users::ImportData::Trips
BATCH_SIZE = 1000
def initialize(user, trips_data)
@user = user
@trips_data = trips_data
end
def call
return 0 unless trips_data.is_a?(Array)
Rails.logger.info "Importing #{trips_data.size} trips for user: #{user.email}"
valid_trips = filter_and_prepare_trips
if valid_trips.empty?
Rails.logger.info "Trips import completed. Created: 0"
return 0
end
deduplicated_trips = filter_existing_trips(valid_trips)
if deduplicated_trips.size < valid_trips.size
Rails.logger.debug "Skipped #{valid_trips.size - deduplicated_trips.size} duplicate trips"
end
total_created = bulk_import_trips(deduplicated_trips)
Rails.logger.info "Trips import completed. Created: #{total_created}"
total_created
end
private
attr_reader :user, :trips_data
def filter_and_prepare_trips
valid_trips = []
skipped_count = 0
trips_data.each do |trip_data|
next unless trip_data.is_a?(Hash)
unless valid_trip_data?(trip_data)
skipped_count += 1
next
end
prepared_attributes = prepare_trip_attributes(trip_data)
valid_trips << prepared_attributes if prepared_attributes
end
if skipped_count > 0
Rails.logger.warn "Skipped #{skipped_count} trips with invalid or missing required data"
end
valid_trips
end
def prepare_trip_attributes(trip_data)
attributes = trip_data.except('created_at', 'updated_at')
attributes['user_id'] = user.id
attributes['created_at'] = Time.current
attributes['updated_at'] = Time.current
attributes.symbolize_keys
rescue StandardError => e
ExceptionReporter.call(e, 'Failed to prepare trip attributes')
nil
end
def filter_existing_trips(trips)
return trips if trips.empty?
existing_trips_lookup = {}
user.trips.select(:name, :started_at, :ended_at).each do |trip|
key = [trip.name, normalize_timestamp(trip.started_at), normalize_timestamp(trip.ended_at)]
existing_trips_lookup[key] = true
end
filtered_trips = trips.reject do |trip|
key = [trip[:name], normalize_timestamp(trip[:started_at]), normalize_timestamp(trip[:ended_at])]
if existing_trips_lookup[key]
Rails.logger.debug "Trip already exists: #{trip[:name]}"
true
else
false
end
end
filtered_trips
end
def normalize_timestamp(timestamp)
case timestamp
when String
Time.parse(timestamp).utc.iso8601
when Time, DateTime
timestamp.utc.iso8601
else
timestamp.to_s
end
rescue StandardError
timestamp.to_s
end
def bulk_import_trips(trips)
total_created = 0
trips.each_slice(BATCH_SIZE) do |batch|
begin
result = Trip.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} trips, created #{batch_created}, total created: #{total_created}"
rescue StandardError => e
ExceptionReporter.call(e, 'Failed to process trip batch')
end
end
total_created
end
def valid_trip_data?(trip_data)
return false unless trip_data.is_a?(Hash)
validate_trip_name(trip_data)
validate_trip_started_at(trip_data)
validate_trip_ended_at(trip_data)
true
rescue StandardError => e
Rails.logger.debug "Trip validation failed: #{e.message} for data: #{trip_data.inspect}"
false
end
def validate_trip_name(trip_data)
unless trip_data['name'].present?
Rails.logger.error 'Failed to create trip: Validation failed: Name can\'t be blank'
return false
end
end
def validate_trip_started_at(trip_data)
unless trip_data['started_at'].present?
Rails.logger.error 'Failed to create trip: Validation failed: Started at can\'t be blank'
return false
end
end
def validate_trip_ended_at(trip_data)
unless trip_data['ended_at'].present?
Rails.logger.error 'Failed to create trip: Validation failed: Ended at can\'t be blank'
return false
end
end
end