class Bullet::Detector::UnusedEagerLoading

def add_eager_loadings(objects, associations)

def add_eager_loadings(objects, associations)
  return unless Bullet.start?
  return unless Bullet.unused_eager_loading_enable?
  return if objects.map(&:bullet_primary_key_value).compact.empty?
  Bullet.debug(
    'Detector::UnusedEagerLoading#add_eager_loadings',
    "objects: #{objects.map(&:bullet_key).join(', ')}, associations: #{associations}"
  )
  bullet_keys = objects.map(&:bullet_key)
  to_add = []
  to_merge = []
  to_delete = []
  eager_loadings.each do |k, _v|
    key_objects_overlap = k & bullet_keys
    next if key_objects_overlap.empty?
    bullet_keys -= k
    if key_objects_overlap == k
      to_add << [k, associations]
    else
      to_merge << [key_objects_overlap, (eager_loadings[k].dup << associations)]
      keys_without_objects = k - key_objects_overlap
      to_merge << [keys_without_objects, eager_loadings[k]]
      to_delete << k
    end
  end
  to_add.each { |k, val| eager_loadings.add k, val }
  to_merge.each { |k, val| eager_loadings.merge k, val }
  to_delete.each { |k| eager_loadings.delete k }
  eager_loadings.add bullet_keys, associations unless bullet_keys.empty?
end

def call_associations(bullet_key, associations)

def call_associations(bullet_key, associations)
  all = Set.new
  eager_loadings.similarly_associated(bullet_key, associations).each do |related_bullet_key|
    coa = call_object_associations[related_bullet_key]
    next if coa.nil?
    all.merge coa
  end
  all.to_a
end

def check_unused_preload_associations

if association not in call_object_association, then the object => association - call_object_association is ununsed preload associations
get call_object_association from associations of call_object_associations whose object is in related_objects
get related_objects from eager_loadings associated with object and associations
check if there are unused preload associations.
def check_unused_preload_associations
  return unless Bullet.start?
  return unless Bullet.unused_eager_loading_enable?
  object_associations.each do |bullet_key, associations|
    object_association_diff = diff_object_associations bullet_key, associations
    next if object_association_diff.empty?
    Bullet.debug('detect unused preload', "object: #{bullet_key}, associations: #{object_association_diff}")
    create_notification(caller_in_project(bullet_key), bullet_key.bullet_class_name, object_association_diff)
  end
end

def create_notification(callers, klazz, associations)

def create_notification(callers, klazz, associations)
  notify_associations = Array.wrap(associations) - Bullet.get_safelist_associations(:unused_eager_loading, klazz)
  if notify_associations.present?
    notice = Bullet::Notification::UnusedEagerLoading.new(callers, klazz, notify_associations)
    Bullet.notification_collector.add(notice)
  end
end

def diff_object_associations(bullet_key, associations)

def diff_object_associations(bullet_key, associations)
  potential_associations = associations - call_associations(bullet_key, associations)
  potential_associations.reject { |a| a.is_a?(Hash) }
end