Fl4m3Ph03n1x
How to execute Ecto.Multi clause conditionally?
Background
I have 3 queries (A, B and C) that need to be run in a transaction. Query A is always run, as well as query B. Query C is run only if query B returns not empty.
These need to be in a transaction, because if query C fails, I want to rollback any changed made by query A.
Code
Currently my code looks like this:
query_A =
# some query
query_B =
# some other query
query_C =
# final query
Multi.new()
|> Multi.update_all(:a, query_A,
set: [update_value: true]
)
|> Multi.all(:all, query_B)
|> Multi.update_all(:c, query_C,
set: [update_other_value: true]
)
|> Repo.transaction()
Problems
There are several problems here:
Multi.alldoes not have an atom associated, so if this operation fails I don’t know how to identify it- I am always running
:c. This is not what I want, I only want to do this if the previousMulti.allreturns non-empty.
Is it possible to achieve this, using Ecto.Multi? I have seen Multi.run but I am unsure on how to make it fit here.
Marked As Solved
Fl4m3Ph03n1x
I have built this query which now seems to work as intended:
Multi.new()
|> Multi.update_all(:a, query_A, set: [update_value: true])
|> Multi.all(:b, query_B)
|> Multi.merge(fn result ->
case result.b do
[] ->
Multi.new()
_ ->
Multi.new()
|> Multi.update_all(:c, query_C, set: [update_other_value: true])
end
end)
|> Repo.transaction()
It is important to notice that query_A should not affect query_B. In case this happens, query_B should be done first (as it is a read only operation).
Thank you all for the help!
Also Liked
LostKobrakai
if Enum.empty?(something.all) do
…
else
…
end
LostKobrakai
Exactly.
LostKobrakai
That doesn’t work, as before running Repo.transaction there’s no way to know if a certain query result will be empty or not.







