defmodule MusicLibrary.Batch do @moduledoc """ Generic batch runner: streams records through a transaction with error accumulation. """ alias MusicLibrary.Repo require Logger @spec run_on_all(Ecto.Queryable.t(), String.t(), (struct() -> :ok | {:ok, term()} | {:error, term()})) :: {:ok, [String.t()]} def run_on_all(queryable, label, fun) do stream = Repo.stream(queryable, max_rows: 50) Repo.transaction( fn -> Enum.reduce(stream, [], fn record, acc -> case fun.(record) do {:error, reason} -> Logger.error( "Failed to run function on #{label} #{record.id} with #{inspect(reason)}" ) [record.id | acc] :ok -> acc {:ok, _result} -> acc end end) end, timeout: :infinity ) end end