Skip to content

Commit b5e6877

Browse files
authored
Add Repo.prepare_transaction/2 (#4605)
1 parent 8e89728 commit b5e6877

File tree

7 files changed

+101
-49
lines changed

7 files changed

+101
-49
lines changed

Diff for: lib/ecto/repo.ex

+35-6
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,12 @@ defmodule Ecto.Repo do
292292
def transaction(fun_or_multi, opts \\ []) do
293293
repo = get_dynamic_repo()
294294

295-
Ecto.Repo.Transaction.transaction(
296-
__MODULE__,
297-
repo,
298-
fun_or_multi,
295+
{adapter_meta, opts} =
299296
Ecto.Repo.Supervisor.tuplet(repo, prepare_opts(:transaction, opts))
300-
)
297+
298+
{fun_or_multi, opts} = prepare_transaction(fun_or_multi, opts)
299+
300+
Ecto.Repo.Transaction.transaction(__MODULE__, repo, fun_or_multi, {adapter_meta, opts})
301301
end
302302

303303
def in_transaction? do
@@ -618,6 +618,9 @@ defmodule Ecto.Repo do
618618

619619
def prepare_query(operation, query, opts), do: {query, opts}
620620
defoverridable prepare_query: 3
621+
622+
def prepare_transaction(fun_or_multi, opts), do: {fun_or_multi, opts}
623+
defoverridable prepare_transaction: 2
621624
end
622625
end
623626
end
@@ -1276,6 +1279,31 @@ defmodule Ecto.Repo do
12761279
{Ecto.Query.t(), Keyword.t()}
12771280
when operation: :all | :update_all | :delete_all | :stream | :insert_all
12781281

1282+
@doc """
1283+
A user-customizable callback invoked on transaction operations.
1284+
1285+
This callback can be used to further modify the given Ecto Multi and options in a transaction operation
1286+
before it is transformed and sent to the database.
1287+
1288+
This callback is only invoked in transactions.
1289+
1290+
## Examples
1291+
1292+
Imagine you want to prepend a SQL comment to commit statements using the `commit_comment` option on transactions.
1293+
1294+
@impl true
1295+
def prepare_transaction(multi_or_fun, opts) do
1296+
opts = Keyword.put_new_lazy(opts, :commit_comment, fn -> extract_comment(opts) end)
1297+
{multi_or_fun, opts}
1298+
end
1299+
1300+
The callback will be invoked for every transaction operation, and it will try to extract the appropriate commit comment,
1301+
that will be subsequently used by the adapters if they support this option.
1302+
"""
1303+
@doc group: "User callbacks"
1304+
@callback prepare_transaction(fun_or_multi :: fun | Ecto.Multi.t(), opts :: Keyword.t()) ::
1305+
{fun_or_multi :: fun | Ecto.Multi.t(), Keyword.t()}
1306+
12791307
@doc """
12801308
A user customizable callback invoked to retrieve default options
12811309
for operations.
@@ -1506,7 +1534,8 @@ defmodule Ecto.Repo do
15061534
delete!: 2,
15071535
insert_or_update: 2,
15081536
insert_or_update!: 2,
1509-
prepare_query: 3
1537+
prepare_query: 3,
1538+
prepare_transaction: 2
15101539

15111540
@doc """
15121541
Inserts all entries into the repository.

Diff for: test/ecto/multi_test.exs

+9-9
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ defmodule Ecto.MultiTest do
292292
assert [{:fun, {:run, _fun}}] = multi.operations
293293

294294
assert {:ok, changes} = TestRepo.transaction(multi)
295-
assert_received {:transaction, _}
295+
assert_received {:transaction, _, _}
296296

297297
assert changes[:fun] == {1, nil}
298298
end
@@ -319,7 +319,7 @@ defmodule Ecto.MultiTest do
319319
assert [{:fun, {:run, _fun}}] = multi.operations
320320

321321
assert {:ok, changes} = TestRepo.transaction(multi)
322-
assert_received {:transaction, _}
322+
assert_received {:transaction, _, _}
323323

324324
assert changes[:fun] == {1, nil}
325325
end
@@ -345,7 +345,7 @@ defmodule Ecto.MultiTest do
345345
assert [{:fun, {:run, _fun}}] = multi.operations
346346

347347
assert {:ok, changes} = TestRepo.transaction(multi)
348-
assert_received {:transaction, _}
348+
assert_received {:transaction, _, _}
349349

350350
assert changes[:fun] == {1, nil}
351351
end
@@ -554,7 +554,7 @@ defmodule Ecto.MultiTest do
554554
|> Multi.delete_all(:delete_all, Comment)
555555

556556
assert {:ok, changes} = TestRepo.transaction(multi)
557-
assert_received {:transaction, _}
557+
assert_received {:transaction, _, _}
558558

559559
assert {:messages,
560560
[
@@ -598,7 +598,7 @@ defmodule Ecto.MultiTest do
598598

599599
test "with empty multi" do
600600
assert {:ok, changes} = TestRepo.transaction(Multi.new())
601-
refute_received {:transaction, _}
601+
refute_received {:transaction, _, _}
602602
assert changes == %{}
603603
end
604604

@@ -613,7 +613,7 @@ defmodule Ecto.MultiTest do
613613
|> Multi.delete(:delete, changeset)
614614

615615
assert {:error, :run, "error from run", changes} = TestRepo.transaction(multi)
616-
assert_received {:transaction, _}
616+
assert_received {:transaction, _, _}
617617
assert_received {:rollback, _}
618618
assert {:messages, [{:insert, %{source: "comments"}}]} = Process.info(self(), :messages)
619619
assert %Comment{} = changes.insert
@@ -636,7 +636,7 @@ defmodule Ecto.MultiTest do
636636
|> Multi.delete(:delete, changeset)
637637

638638
assert {:error, :update, error, changes} = TestRepo.transaction(multi)
639-
assert_received {:transaction, _}
639+
assert_received {:transaction, _, _}
640640
assert_received {:rollback, _}
641641
assert {:messages, [{:insert, %{source: "comments"}}]} = Process.info(self(), :messages)
642642
assert %Comment{} = changes.insert
@@ -657,14 +657,14 @@ defmodule Ecto.MultiTest do
657657

658658
assert {:error, :invalid, invalid, %{}} = TestRepo.transaction(multi)
659659
assert invalid.data == changeset.data
660-
refute_received {:transaction, _}
660+
refute_received {:transaction, _, _}
661661
end
662662

663663
test "checks error operation before starting transaction" do
664664
multi = Multi.new() |> Multi.error(:invalid, "error")
665665

666666
assert {:error, :invalid, "error", %{}} = TestRepo.transaction(multi)
667-
refute_received {:transaction, _}
667+
refute_received {:transaction, _, _}
668668
end
669669
end
670670

Diff for: test/ecto/repo/belongs_to_test.exs

+8-8
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ defmodule Ecto.Repo.BelongsToTest do
153153
refute changeset.valid?
154154

155155
# Just one transaction was used
156-
assert_received {:transaction, _}
156+
assert_received {:transaction, _, _}
157157
assert_received {:rollback, ^changeset}
158-
refute_received {:transaction, _}
158+
refute_received {:transaction, _, _}
159159
refute_received {:rollback, _}
160160
end
161161

@@ -174,7 +174,7 @@ defmodule Ecto.Repo.BelongsToTest do
174174
assert schema.assoc.sub_assoc_id == schema.assoc.sub_assoc.id
175175

176176
# Just one transaction was used
177-
assert_received {:transaction, _}
177+
assert_received {:transaction, _, _}
178178
refute_received {:rollback, _}
179179
end
180180

@@ -212,9 +212,9 @@ defmodule Ecto.Repo.BelongsToTest do
212212
refute changeset.valid?
213213

214214
# Just one transaction was used
215-
assert_received {:transaction, _}
215+
assert_received {:transaction, _, _}
216216
assert_received {:rollback, ^changeset}
217-
refute_received {:transaction, _}
217+
refute_received {:transaction, _, _}
218218
refute_received {:rollback, _}
219219
end
220220

@@ -444,7 +444,7 @@ defmodule Ecto.Repo.BelongsToTest do
444444
assert schema.assoc.sub_assoc.id
445445

446446
# One transaction was used
447-
assert_received {:transaction, _}
447+
assert_received {:transaction, _, _}
448448
refute_received {:rollback, _}
449449
end
450450

@@ -469,9 +469,9 @@ defmodule Ecto.Repo.BelongsToTest do
469469
refute changeset.valid?
470470

471471
# Just one transaction was used
472-
assert_received {:transaction, _}
472+
assert_received {:transaction, _, _}
473473
assert_received {:rollback, ^changeset}
474-
refute_received {:transaction, _}
474+
refute_received {:transaction, _, _}
475475
refute_received {:rollback, _}
476476
end
477477

Diff for: test/ecto/repo/has_assoc_test.exs

+8-8
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,9 @@ defmodule Ecto.Repo.HasAssocTest do
215215
refute changeset.valid?
216216

217217
# Just one transaction was used
218-
assert_received {:transaction, _}
218+
assert_received {:transaction, _, _}
219219
assert_received {:rollback, ^changeset}
220-
refute_received {:transaction, _}
220+
refute_received {:transaction, _, _}
221221
refute_received {:rollback, _}
222222
end
223223

@@ -234,7 +234,7 @@ defmodule Ecto.Repo.HasAssocTest do
234234
assert schema.assoc.sub_assoc.id
235235

236236
# Just one transaction was used
237-
assert_received {:transaction, _}
237+
assert_received {:transaction, _, _}
238238
refute_received {:rollback, _}
239239
end
240240

@@ -271,9 +271,9 @@ defmodule Ecto.Repo.HasAssocTest do
271271
refute changeset.valid?
272272

273273
# Just one transaction was used
274-
assert_received {:transaction, _}
274+
assert_received {:transaction, _, _}
275275
assert_received {:rollback, ^changeset}
276-
refute_received {:transaction, _}
276+
refute_received {:transaction, _, _}
277277
refute_received {:rollback, _}
278278
end
279279

@@ -573,7 +573,7 @@ defmodule Ecto.Repo.HasAssocTest do
573573
assert schema.assoc.sub_assoc.id
574574

575575
# One transaction was used
576-
assert_received {:transaction, _}
576+
assert_received {:transaction, _, _}
577577
refute_received {:rollback, _}
578578
end
579579

@@ -598,9 +598,9 @@ defmodule Ecto.Repo.HasAssocTest do
598598
refute changeset.valid?
599599

600600
# Just one transaction was used
601-
assert_received {:transaction, _}
601+
assert_received {:transaction, _, _}
602602
assert_received {:rollback, ^changeset}
603-
refute_received {:transaction, _}
603+
refute_received {:transaction, _, _}
604604
refute_received {:rollback, _}
605605
end
606606

Diff for: test/ecto/repo/many_to_many_test.exs

+8-8
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,9 @@ defmodule Ecto.Repo.ManyToManyTest do
274274
refute changeset.valid?
275275

276276
# Just one transaction was used
277-
assert_received {:transaction, _}
277+
assert_received {:transaction, _, _}
278278
assert_received {:rollback, ^changeset}
279-
refute_received {:transaction, _}
279+
refute_received {:transaction, _, _}
280280
refute_received {:rollback, _}
281281
refute_received {:insert_all, _, _}
282282
end
@@ -294,7 +294,7 @@ defmodule Ecto.Repo.ManyToManyTest do
294294
assert hd(schema.assocs).sub_assoc.id
295295

296296
# Just one transaction was used
297-
assert_received {:transaction, _}
297+
assert_received {:transaction, _, _}
298298
refute_received {:rollback, _}
299299
assert_received {:insert_all, %{source: "schemas_assocs"}, [[my_assoc_id: 1, my_schema_id: 1]]}
300300
end
@@ -332,9 +332,9 @@ defmodule Ecto.Repo.ManyToManyTest do
332332
refute Map.has_key?(assoc.changes.sub_assoc.changes, :id)
333333

334334
# Just one transaction was used
335-
assert_received {:transaction, _}
335+
assert_received {:transaction, _, _}
336336
assert_received {:rollback, ^changeset}
337-
refute_received {:transaction, _}
337+
refute_received {:transaction, _, _}
338338
refute_received {:rollback, _}
339339
refute_received {:insert_all, _, _}
340340
end
@@ -624,7 +624,7 @@ defmodule Ecto.Repo.ManyToManyTest do
624624
assert hd(schema.assocs).sub_assoc.id
625625

626626
# One transaction was used
627-
assert_received {:transaction, _}
627+
assert_received {:transaction, _, _}
628628
refute_received {:rollback, _}
629629
refute_received {:insert_all, _, _}
630630
end
@@ -652,9 +652,9 @@ defmodule Ecto.Repo.ManyToManyTest do
652652
refute Map.has_key?(assoc.changes.sub_assoc.changes, :my_assoc_id)
653653

654654
# Just one transaction was used
655-
assert_received {:transaction, _}
655+
assert_received {:transaction, _, _}
656656
assert_received {:rollback, ^changeset}
657-
refute_received {:transaction, _}
657+
refute_received {:transaction, _, _}
658658
refute_received {:rollback, _}
659659
refute_received {:insert_all, _, _}
660660
end

0 commit comments

Comments
 (0)