Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 90 additions & 0 deletions integration_test/cases/repo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2304,4 +2304,94 @@ defmodule Ecto.Integration.RepoTest do
defp uuid_module(Ecto.Adapters.Tds), do: Tds.Ecto.UUID
defp uuid_module(_), do: Ecto.UUID
end

describe "transact/2 with function" do
test "return ok" do
assert {:ok, [post1, post2]} =
TestRepo.transact(fn ->
post1 = TestRepo.insert!(%Post{title: "1"})
post2 = TestRepo.insert!(%Post{title: "2"})
{:ok, [post1, post2]}
end)

assert TestRepo.all(Post) |> Enum.sort() == [post1, post2]
end

test "return error" do
assert {:error, :oops} =
TestRepo.transact(fn ->
TestRepo.insert!(%Post{title: "1"})
TestRepo.insert!(%Post{title: "2"})
{:error, :oops}
end)

assert TestRepo.all(Post) == []
end

test "rollback" do
assert {:error, :oops} =
TestRepo.transact(fn ->
TestRepo.insert!(%Post{title: "1"})
TestRepo.insert!(%Post{title: "2"})
TestRepo.rollback(:oops)
raise "unreachable"
end)

assert TestRepo.all(Post) == []
end

test "raise error" do
assert_raise RuntimeError, "oops", fn ->
TestRepo.transact(fn ->
TestRepo.insert!(%Post{title: "1"})
TestRepo.insert!(%Post{title: "2"})
raise "oops"
end)
end

assert TestRepo.all(Post) == []
end
end

describe "transact/2 with multi" do
test "ok" do
multi = Ecto.Multi.new()
|> Ecto.Multi.insert(:post1, %Post{title: "1"})
|> Ecto.Multi.insert(:post2, %Post{title: "2"})

assert {:ok, %{post1: post1, post2: post2}} =
TestRepo.transact(multi)

assert TestRepo.all(Post) |> Enum.sort() == [post1, post2]
end

test "error" do
changeset =
Ecto.Changeset.change(%Post{})
|> Ecto.Changeset.add_error(:title, "invalid")

multi =
Ecto.Multi.new()
|> Ecto.Multi.insert(:post1, %Post{title: "1"})
|> Ecto.Multi.insert(:post2, fn _ -> changeset end)

assert {:error, :post2, changeset, %{post1: %Post{title: "1"}}} =
TestRepo.transact(multi)

refute changeset.valid?
end
end

describe "transaction/2 (soft-deprecated)" do
test "ok" do
assert {:ok, {:ok, [post1, post2]}} =
TestRepo.transaction(fn ->
post1 = TestRepo.insert!(%Post{title: "1"})
post2 = TestRepo.insert!(%Post{title: "2"})
{:ok, [post1, post2]}
end)

assert TestRepo.all(Post) |> Enum.sort() == [post1, post2]
end
end
end
48 changes: 24 additions & 24 deletions lib/ecto/multi.ex
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ defmodule Ecto.Multi do

We can later execute it in the integration layer using Repo:

Repo.transaction(PasswordManager.reset(account, params))
Repo.transact(PasswordManager.reset(account, params))

By pattern matching on the result we can differentiate different conditions:

Expand Down Expand Up @@ -253,7 +253,7 @@ defmodule Ecto.Multi do
Ecto.Multi.new()
|> Ecto.Multi.insert(:comment, Ecto.build_assoc(post, :comments))
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()
"""
@spec merge(t, (changes -> t)) :: t
def merge(%Multi{} = multi, merge) when is_function(merge, 1) do
Expand Down Expand Up @@ -286,14 +286,14 @@ defmodule Ecto.Multi do

Ecto.Multi.new()
|> Ecto.Multi.insert(:insert, %Post{title: "first"})
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.insert(:post, %Post{title: "first"})
|> Ecto.Multi.insert(:comment, fn %{post: post} ->
Ecto.build_assoc(post, :comments)
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

"""
@spec insert(
Expand Down Expand Up @@ -329,14 +329,14 @@ defmodule Ecto.Multi do
changeset = Ecto.Changeset.change(post, title: "New title")
Ecto.Multi.new()
|> Ecto.Multi.update(:update, changeset)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.insert(:post, %Post{title: "first"})
|> Ecto.Multi.update(:fun, fn %{post: post} ->
Ecto.Changeset.change(post, title: "New title")
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

"""
@spec update(t, name, Changeset.t() | fun(Changeset.t()), Keyword.t()) :: t
Expand All @@ -362,7 +362,7 @@ defmodule Ecto.Multi do
changeset = Post.changeset(%Post{}, %{title: "New title"})
Ecto.Multi.new()
|> Ecto.Multi.insert_or_update(:insert_or_update, changeset)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.run(:post, fn repo, _changes ->
Expand All @@ -371,7 +371,7 @@ defmodule Ecto.Multi do
|> Ecto.Multi.insert_or_update(:update, fn %{post: post} ->
Ecto.Changeset.change(post, title: "New title")
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

"""
@spec insert_or_update(t, name, Changeset.t() | fun(Changeset.t()), Keyword.t()) :: t
Expand Down Expand Up @@ -406,7 +406,7 @@ defmodule Ecto.Multi do
post = MyApp.Repo.get!(Post, 1)
Ecto.Multi.new()
|> Ecto.Multi.delete(:delete, post)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.run(:post, fn repo, _changes ->
Expand All @@ -419,7 +419,7 @@ defmodule Ecto.Multi do
# Others validations
post
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

"""
@spec delete(
Expand Down Expand Up @@ -456,7 +456,7 @@ defmodule Ecto.Multi do
|> Ecto.Multi.one(:author, fn %{post: post} ->
from(a in Author, where: a.id == ^post.author_id)
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()
"""
@spec one(
t,
Expand Down Expand Up @@ -485,11 +485,11 @@ defmodule Ecto.Multi do

Ecto.Multi.new()
|> Ecto.Multi.all(:all, Post)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.all(:all, fn _changes -> Post end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()
"""
@spec all(
t,
Expand Down Expand Up @@ -518,11 +518,11 @@ defmodule Ecto.Multi do

Ecto.Multi.new()
|> Ecto.Multi.exists?(:post, Post)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.exists?(:post, fn _changes -> Post end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()
"""
@spec exists?(
t,
Expand Down Expand Up @@ -614,7 +614,7 @@ defmodule Ecto.Multi do
posts = [%{title: "My first post"}, %{title: "My second post"}]
Ecto.Multi.new()
|> Ecto.Multi.insert_all(:insert_all, Post, posts)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.run(:post, fn repo, _changes ->
Expand All @@ -631,7 +631,7 @@ defmodule Ecto.Multi do
Map.put(comment, :post_id, post.id)
end)
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

"""
@spec insert_all(
Expand Down Expand Up @@ -662,7 +662,7 @@ defmodule Ecto.Multi do

Ecto.Multi.new()
|> Ecto.Multi.update_all(:update_all, Post, set: [title: "New title"])
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.run(:post, fn repo, _changes ->
Expand All @@ -675,7 +675,7 @@ defmodule Ecto.Multi do
# Others validations
from(c in Comment, where: c.post_id == ^post.id, update: [set: [title: "New title"]])
end, [])
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

"""
@spec update_all(
Expand Down Expand Up @@ -707,7 +707,7 @@ defmodule Ecto.Multi do
queryable = from(p in Post, where: p.id < 5)
Ecto.Multi.new()
|> Ecto.Multi.delete_all(:delete_all, queryable)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Ecto.Multi.new()
|> Ecto.Multi.run(:post, fn repo, _changes ->
Expand All @@ -720,7 +720,7 @@ defmodule Ecto.Multi do
# Others validations
from(c in Comment, where: c.post_id == ^post.id)
end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

"""
@spec delete_all(t, name, Ecto.Queryable.t() | fun(Ecto.Queryable.t()), Keyword.t()) :: t
Expand Down Expand Up @@ -781,7 +781,7 @@ defmodule Ecto.Multi do
|> Ecto.Multi.put(:company, company)
|> Ecto.Multi.insert(:user, fn changes -> User.changeset(changes.company) end)
|> Ecto.Multi.insert(:person, fn changes -> Person.changeset(changes.user, changes.company) end)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

In the example above there isn't a large benefit in putting the
`company` in the multi, because you could also access the
Expand Down Expand Up @@ -817,7 +817,7 @@ defmodule Ecto.Multi do
|> Ecto.Multi.insert(:person_a, changeset)
|> Ecto.Multi.insert(:person_b, changeset)
|> Ecto.Multi.inspect()
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Prints:
%{person_a: %Person{...}, person_b: %Person{...}}
Expand All @@ -828,7 +828,7 @@ defmodule Ecto.Multi do
|> Ecto.Multi.insert(:person_a, changeset)
|> Ecto.Multi.insert(:person_b, changeset)
|> Ecto.Multi.inspect(only: :person_a)
|> MyApp.Repo.transaction()
|> MyApp.Repo.transact()

Prints:
%{person_a: %Person{...}}
Expand Down
Loading
Loading