`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.