vol1ura/Sat_9am_5km

View on GitHub
app/jobs/home_badge_awarding_job.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
# frozen_string_literal: true

class HomeBadgeAwardingJob < ApplicationJob
  queue_as :low

  def perform(athlete_id = nil)
    utmost_badge = Badge.new(info: { threshold: 10**10 })
    Badge::BADGE_TYPES.each do |type|
      badges_dataset = Badge.dataset_of(kind: :home_participating, type: type)
      badges_dataset.to_a.push(utmost_badge).each_cons(2) do |badge, next_badge|
        athlete_ids =
          athlete_ids_ds(type, min_events_count: badge.info['threshold'], max_events_count: next_badge.info['threshold'])
        athlete_ids = athlete_ids.where(athlete_id:) if athlete_id

        Athlete.where(id: athlete_ids).where.not(id: badge.trophies.select(:athlete_id)).find_each do |athlete|
          athlete.transaction do
            athlete.trophies.where(badge: badges_dataset.where.not(id: badge.id)).destroy_all
            athlete.trophies.create! badge: badge, date: date_of_awarding(athlete, badge)
          end
        end
      end
    end
  end

  private

  def athlete_ids_ds(type, min_events_count:, max_events_count:)
    type
      .camelize
      .constantize
      .published
      .joins(:athlete)
      .where('activity.event_id = athletes.event_id')
      .group(:athlete_id)
      .having('COUNT(*) >= ? AND COUNT(*) < ?', min_events_count, max_events_count)
      .select(:athlete_id)
  end

  def date_of_awarding(athlete, badge)
    athlete
      .send(Badge::ASSOCIATION_TYPE_MAPPING[badge.info['type']])
      .published
      .where(activity: { event: athlete.event })
      .reorder('activity.date')
      .select('activity.date')
      .offset(badge.info['threshold'].pred)
      .first[:date]
  end
end