# frozen_string_literal: true class Photos::Importer include Imports::Broadcaster include Imports::FileLoader include PointValidation BATCH_SIZE = 1000 attr_reader :import, :user_id, :file_path def initialize(import, user_id, file_path = nil) @import = import @user_id = user_id @file_path = file_path end def call json = load_json_data points_data = json.map { |point| prepare_point_data(point) } points_data.compact.each_slice(BATCH_SIZE).with_index do |batch, batch_index| bulk_insert_points(batch) broadcast_import_progress(import, (batch_index + 1) * BATCH_SIZE) end end private def prepare_point_data(point) return nil unless valid?(point) { lonlat: point['lonlat'], longitude: point['longitude'], latitude: point['latitude'], timestamp: point['timestamp'].to_i, raw_data: point, import_id: import.id, user_id: user_id, created_at: Time.current, updated_at: Time.current } end def bulk_insert_points(batch) unique_batch = batch.uniq { |record| [record[:lonlat], record[:timestamp], record[:user_id]] } # rubocop:disable Rails/SkipsModelValidations Point.upsert_all( unique_batch, unique_by: %i[lonlat timestamp user_id], returning: false, on_duplicate: :skip ) # rubocop:enable Rails/SkipsModelValidations rescue StandardError => e create_notification("Failed to process photo location batch: #{e.message}") end def create_notification(message) Notification.create!( user_id: user_id, title: 'Photos Import Error', content: message, kind: :error ) end def valid?(point) point['latitude'].present? && point['longitude'].present? && point['timestamp'].present? end end