lib/ash/flow/transformers/set_api.ex

defmodule Ash.Flow.Transformers.SetApi do
  @moduledoc "Sets the api on the steps of a flow to the default api, unless an api is set explicitly."
  use Spark.Dsl.Transformer
  alias Spark.Dsl.Transformer

  def before?(_), do: true

  def transform(dsl_state) do
    api = Transformer.get_option(dsl_state, [:flow], :api)

    dsl_state
    |> Transformer.get_entities([:steps])
    |> Enum.map(&set_api(&1, api))
    |> Enum.reduce({:ok, dsl_state}, fn step, {:ok, dsl_state} ->
      {:ok,
       Spark.Dsl.Transformer.replace_entity(
         dsl_state,
         [:steps],
         step,
         &(&1.name == step.name)
       )}
    end)
  end

  def set_api(step, default) do
    if Map.has_key?(step, :api) do
      step = %{step | api: step.api || default}

      if step.api do
        step
      else
        raise Spark.Error.DslError,
          path: [:flow, :steps, step.name, :api],
          message:
            "Api is required for #{step.__struct__} steps. A default one can be provided in the `flow` section."
      end
    else
      step
    end
    |> set_nested_apis(default)
  end

  defp set_nested_apis(%{steps: steps} = step, default) do
    %{step | steps: Enum.map(steps, &set_api(&1, default))}
  end

  defp set_nested_apis(step, _), do: step
end