Pattern matching with Ecto.Multi

I’ve changed a function that inserts a record into a table to use a Ecto.Multi inserting the record and updating another one in a different table. This seems to work, but I’m struggling with the unit test when trying to insert invalid data.

So here’s my function:

def create_bin(%User{} = user, attrs \\ %{}) do
  user_changeset =
    user
    |> User.synchronization_timestamp_changeset(%{synchronization_timestamp: DateTime.utc_now()})

  bin_changeset = %Bin{}
    |> Bin.changeset(attrs)

  Ecto.Multi.new()
  |> Ecto.Multi.update(:user, user_changeset)
  |> Ecto.Multi.insert(:bin, bin_changeset)
  |> Repo.transaction()
end

And here’s the unit test:

test "create_bin/1 with invalid data returns error changeset" do
  assert {:error, :bin, %Ecto.Changeset{}} = UserData.create_bin(test_user, @invalid_attrs)
end

But the test fails with the following output:

 match (=) failed
 code:  assert {:error, :bin, %Ecto.Changeset{}} = UserData.create_bin(test_user, @invalid_attrs)
 left:  {:error, :bin, #Ecto.Changeset<action: nil, changes: %{}, errors: [], data: nil, valid?: false>}
 right: {
          :error,
          :bin,
          #Ecto.Changeset<action: :insert, changes: %{}, errors: [user_id: {"can't be blank", [validation: :required]}, name: {"can't be blank", [validation: :required]}], data: #IvvServer.UserData.Bin<>, valid?: false>,
          %{}
        }

Obviously, the pattern matching is the issue, but I can’t figure out how to fix it. Can somebody please help?

Repo.transaction for multi actually return error as following spec {:error, Ecto.Multi.name(), any(), %{required(Ecto.Multi.name()) => any()}}, which is usually named as {:error, multi_name, error, changes}.

Your test doesn’t consider changes as part of the assertion. to fix it you need to change it to assert {:error, :bin, _changeset, _changes}

1 Like

also, usually function such as create_bin should not expose error return of Repo.transaction directly, rather return error which are already handled into regular error format, like {:error, error_atom} or {:error, error_message}. usually it would be create_bin job to translate result of Repo.transaction into these regular format.

1 Like

Many thanks for help, I actually according to your input and everything works as expected.