Maintenance::SetFirstMboProfileAsPrimaryTask

Source code
# frozen_string_literal: true

# Remediates tree nodes whose MBO profile join records have no primary entry.
# This can occur when BackfillTreeNodeToMboProfilesTask ran against profiles that
# had primary: false, or when it was never run before the old columns were dropped.
#
# Safe to re-run: the collection query excludes tree nodes that already have a primary.
# `process` reloads and skips if a primary was created concurrently (e.g. live traffic).
class Maintenance::SetFirstMboProfileAsPrimaryTask < MaintenanceTasks::Task
  collection_batch_size(1_000)

  def collection
    TreeNode.joins(:tree_node_to_mbo_profiles)
            .where.not(
              id: TreeNodeToMboProfile.where(primary: true).select(:tree_node_id)
            )
            .distinct
  end

  def process(tree_node)
    tree_node.reload
    return if tree_node.tree_node_to_mbo_profiles.exists?(primary: true)

    join = tree_node.tree_node_to_mbo_profiles.order(created_at: :asc, id: :asc).first
    return unless join

    join.update!(primary: true)
  rescue ActiveRecord::RecordNotUnique
    nil
  rescue ActiveRecord::RecordInvalid => e
    raise e unless e.record.errors.of_kind?(:primary, :taken)
  end
end