How could I access the changes from this?

ok, so what I am trying to do is the following:
I have my multi started here:

multi =
      Enum.reduce(participants, Multi.new(), fn p, mult ->
        invited_user =
          cond do
            p["user_id"] != nil ->
              Accounts.get_user_by_hash_id(p["user_id"])

            p["email"] != nil ->
              update_or_keep_the_user(mult, "email", p)

              Accounts.get_user_by_email(p["email"])

            p["phone_number"] != nil ->
              update_or_keep_the_user(mult, "phone", p)

            true ->
              nil
          end

and then i want to use the user that should be returned.
but as you see at the email one i call Accounts.get_user_by_email(p["email"]) but that returns the old one, and to see the update_or_keep_the_user(mult, "phone", p) here:

defp update_or_keep_the_user(multi, type, p) when type in ["phone", "email"] do
    old_user =
      case type do
        "email" -> Accounts.get_user_by_email(p["email"])
        "phone" -> Accounts.get_user_by_phone_number(p["phone_number"])
      end

    if old_user do
      old_user_profile = Accounts.get_profile_by_user(old_user.id)

      account_changeset =
        cond do
          is_nil(p["last_name"]) or p["last_name"] == "" ->
            Accounts.Profile.changeset(old_user_profile, %{
              first_name: p["first_name"],
              email: p["emai;"]
            })

          true ->
            Accounts.Profile.changeset(old_user_profile, %{
              first_name: p["first_name"],
              last_name: p["last_name"],
              phone_number: p["phone_number"]
            })
        end

      multi
      |> Multi.run(:profile, fn _repo, account_changeset ->
        Repo.update(account_changeset)
      end)
      |> Multi.run(:user, fn _repo, old_user ->
        Accounts.get_user(old_user.id)
      end)
    end
  end

so I am tryng to update the user and get it after to use it inside the multi.
What is wrong with this?

Your whole function is being set to a binding named multi so shouldnā€™t Accounts.get_user_by_email(p["email"]) return a multi and not a user then?

When using multiā€™s you want the entire path to be a multi chained from one to the next to the next as they are a series of steps run in order. From an initial guess Iā€™d imagine you want that whole expression to be something more like:

multi =
      Enum.reduce(participants, Multi.new(), fn p, mult ->
        invited_user =
          cond do
            p["user_id"] != nil ->
              Multi.run(multi, "user", fn(_repo, _changes) -> Accounts.get_user_by_hash_id(p["user_id"]) end)

            p["email"] != nil ->
              update_or_keep_the_user(mult, "email", p)
              |> Multi.run("email", fn(_repo, _changes) -> Accounts.get_user_by_email(p["email"]) end)

            p["phone_number"] != nil ->
              update_or_keep_the_user(mult, "phone", p)

            true ->
              multi
          end

I.E. you need to encode all steps into the multi where anything depends on anything else. That is how database transactions work. :slight_smile:

In essence, by getting the record from before Repo.run() is run for the multi gets you the old data, and from ā€˜withinā€™ the multi or after running Repo.run() on the multi then it is the new data. Transactions are atomic, they either fully succeed or fully fail and you donā€™t get information that happened inside the transaction to the outside until the transaction is fully committed.

1 Like