Proposals on Repo.transact/2

53 views
Skip to first unread message

zekedou

unread,
Jun 20, 2025, 6:00:59 AMJun 20
to elixir-ecto
`Repo.transact/2` is added in Ecto v3.13. That's great.

In the intended design:
- `Repo.transact/2`'s `fun` argument is expected to return `{:ok, result}` or `{:error, reason}`.
- `Repo.transact/2` itself will return `{:ok, result}` or `{:error, reason}`.

But sometimes, the `fun` may not produce a meaningful `result` value. In such cases, returning `:ok` might be more appropriate.

However, `Repo.transact/2` in Ecto does not support this usage by default and requires additional handling. Before Ecto natively introduced its own `Repo.transact/2`, I was using the `Repo.transact/2` implementation written by Saša Jurić (https://github.com/sasa1977/mix_phx_alt/blob/d33a67fd6b2fa0ace5b6206487e774ef7a22ce5a/lib/core/repo.ex#L21).

Now that Ecto has added its own `Repo.transact/2`, I’ve had to rename Saša's version. But when renaming it to something else, it loses the readability and clarity conveyed by the name *transact*.

Perhaps, I should enhance Ecto's built-in `Repo.transact/2` to make it more convenient to use. Therefore, I have a proposal —— to extend `Repo.transact/2` with support for returning `:ok` and `:error`, so that it can be used more conveniently.

The general idea is as follows:

```Elixir
  def transact(repo, _name, fun, {adapter_meta, opts}) when is_function(fun, 0) do
    transaction_result =
      adapter_meta.adapter.transaction(adapter_meta, opts, fn ->
        case fun.() do
          :ok ->
            {__MODULE__, :transact, :ok}

          :error ->
            rollback({__MODULE__, :transact, :error})

          {:ok, result} ->
            result

          {:error, reason} ->
            rollback(repo, reason)

          other ->
            raise ArgumentError,
                  "expected to return :ok, :error, {:ok, _} or {:error, _}, got: #{inspect(other)}"
        end
      end)

    with {outcome, {__MODULE__, :transact, outcome}}
         when outcome in [:ok, :error] <- transaction_result,
         do: outcome
  end
```

Essentially, it would be an integration of Ecto's current `Repo.transact/2` and Saša Jurić's version of `Repo.transact/2`, designed to support more use cases.

What do you think of this idea? If you believe it's a good one, I'd be happy to contribute the code.
Reply all
Reply to author
Forward
0 new messages