Skip to content

Commit 8fbf588

Browse files
committed
Release v3.13.0
1 parent abc1624 commit 8fbf588

4 files changed

Lines changed: 13 additions & 97 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@ Requires Elixir v1.14+.
1616
* [Ecto.Query] Allow source fields in `json_extract_path`
1717
* [Ecto.Repo] Add `Ecto.Repo.prepare_transaction/2` user callback
1818
* [Ecto.Repo] Add `Ecto.Repo.all_by/3`
19+
* [Ecto.Repo] Add `Ecto.Repo.transact/2`
20+
* [Ecto.Repo] Allow HOT updates on upsert queries in Postgres by removing duplicate fields during `replace` and `replace_all_except`
1921
* [Ecto.Schema] Support `@schema_redact: :all_except_primary_keys` module attribute
2022

2123
### Bug fixes
2224

2325
* [Ecto.Query] Allow select merging maps with all nil values
2426
* [Ecto.Schema] Fix an issue where Ecto could warn an association did not exist, when it did
2527

28+
### Deprecations
29+
30+
* [Ecto.Repo] `Ecto.Repo.transaction/2` is soft-deprecated in favor of `Ecto.Repo.transaction/1`
31+
2632
## v3.12.6 (2025-06-11)
2733

2834
Fix deprecations on Elixir v1.19.
@@ -85,7 +91,7 @@ Fix deprecations on Elixir v1.19.
8591
* [Ecto.Query] Allow map updates with dynamic values in `select`
8692
* [Ecto.Query] Allow any data structure that implements the Enumerable protocol on the right side of `in`
8793
* [Ecto.Repo] Support 2-arity preload functions that receive ids and the association metadata
88-
* [Ecto.Repo] Allow Hot Updates on upsert queries in Postgres by removing duplicate fields during replace_all
94+
* [Ecto.Repo] Allow HOT updates on upsert queries in Postgres by removing duplicate fields during `replace_all`
8995
* [Ecto.Repo] `insert_all` supports queries with only source
9096
* [Ecto.Repo] `insert_all` supports queries with the update syntax
9197
* [Ecto.Repo] Support `:allow_stale` on Repo struct/changeset operations

lib/ecto/repo.ex

Lines changed: 3 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2180,6 +2180,8 @@ defmodule Ecto.Repo do
21802180
@doc """
21812181
Runs the given function or `Ecto.Multi` inside a transaction.
21822182
2183+
Deprecated in favor of `c:transact/2`.
2184+
21832185
## Use with function
21842186
21852187
`c:transaction/2` can be called with both a function of arity
@@ -2209,42 +2211,7 @@ defmodule Ecto.Repo do
22092211
A successful transaction returns the value returned by the function
22102212
wrapped in a tuple as `{:ok, value}`.
22112213
2212-
### Nested transactions
2213-
2214-
If `c:transaction/2` is called inside another transaction, the function
2215-
is simply executed, without wrapping the new transaction call in any
2216-
way. If there is an error in the inner transaction and the error is
2217-
rescued, or the inner transaction is rolled back, the whole outer
2218-
transaction is aborted, guaranteeing nothing will be committed.
2219-
2220-
Below is an example of how rollbacks work with nested transactions:
2221-
2222-
{:error, :rollback} =
2223-
MyRepo.transaction(fn ->
2224-
{:error, :posting_not_allowed} =
2225-
MyRepo.transaction(fn ->
2226-
# This function call causes the following to happen:
2227-
#
2228-
# * the transaction is rolled back in the database,
2229-
# * code execution is stopped within the current function,
2230-
# * and the value, passed to `rollback/1` is returned from
2231-
# `MyRepo.transaction/1` as the second element in the error
2232-
# tuple.
2233-
#
2234-
MyRepo.rollback(:posting_not_allowed)
2235-
2236-
# `rollback/1` stops execution, so code here won't be run
2237-
end)
2238-
2239-
# The transaction here is now aborted and any further
2240-
# operation will raise an exception.
2241-
end)
2242-
2243-
See the ["Aborted transactions"](`c:transaction/2#aborted-transactions`) section for more examples of aborted
2244-
transactions and how to handle them.
2245-
2246-
In practice, managing nested transactions can become complex quickly.
2247-
For this reason, Ecto provides `Ecto.Multi` for composing transactions.
2214+
See `c:transact/2` for further considerations.
22482215
22492216
## Use with Ecto.Multi
22502217
@@ -2265,63 +2232,6 @@ defmodule Ecto.Repo do
22652232
22662233
Explore the `Ecto.Multi` documentation to learn more and find detailed examples.
22672234
2268-
## Aborted transactions
2269-
2270-
When an operation inside a transaction fails, the transaction is aborted in the database.
2271-
For instance, if you attempt an insert that violates a unique constraint, the insert fails
2272-
and the transaction is aborted. In such cases, any further operation inside the transaction
2273-
will raise exceptions.
2274-
2275-
Take the following transaction as an example:
2276-
2277-
Repo.transaction(fn repo ->
2278-
case repo.insert(changeset) do
2279-
{:ok, post} ->
2280-
repo.insert(%Status{value: "success"})
2281-
2282-
{:error, changeset} ->
2283-
repo.insert(%Status{value: "failure"})
2284-
end
2285-
end)
2286-
2287-
If the changeset is valid, but the insert operation fails due to a database constraint,
2288-
the subsequent `repo.insert(%Status{value: "failure"})` operation will raise an exception
2289-
because the database has already aborted the transaction and thus making the operation invalid.
2290-
In Postgres, the exception would look like this:
2291-
2292-
** (Postgrex.Error) ERROR 25P02 (in_failed_sql_transaction) current transaction is aborted, commands ignored until end of transaction block
2293-
2294-
If the changeset is invalid before it reaches the database due to a validation error,
2295-
no statement is sent to the database, an `:error` tuple is returned, and `repo.insert(%Status{value: "failure"})`
2296-
operation will execute as usual.
2297-
2298-
We have two options to deal with such scenarios:
2299-
2300-
If you don't want to change the semantics of your code, you can also use the savepoints
2301-
feature by passing the `:mode` option like this: `repo.insert(changeset, mode: :savepoint)`.
2302-
In case of an exception, the transaction will rollback to the savepoint and prevent
2303-
the transaction from failing.
2304-
2305-
Another alternative is to handle this operation outside of the transaction.
2306-
For example, you can choose to perform an explicit `repo.rollback` call in the
2307-
`{:error, changeset}` clause and then perform the `repo.insert(%Status{value: "failure"})` outside
2308-
of the transaction. You might also consider using `Ecto.Multi`, as they automatically
2309-
rollback whenever an operation fails.
2310-
2311-
## Working with processes
2312-
2313-
The transaction is per process. A separate process started inside a
2314-
transaction won't be part of the same transaction and will use a separate
2315-
connection altogether.
2316-
2317-
When using the `Ecto.Adapters.SQL.Sandbox` in tests, while it may be
2318-
possible to share the connection between processes, the parent process
2319-
will typically hold the connection until the transaction completes. This
2320-
may lead to a deadlock if the child process attempts to use the same connection.
2321-
See the docs for
2322-
[`Ecto.Adapters.SQL.Sandbox`](https://hexdocs.pm/ecto_sql/Ecto.Adapters.SQL.Sandbox.html)
2323-
for more information.
2324-
23252235
## Options
23262236
23272237
See the ["Shared options"](#module-shared-options) section at the module

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ defmodule Ecto.MixProject do
22
use Mix.Project
33

44
@source_url "https://github.com/elixir-ecto/ecto"
5-
@version "3.13.0-dev"
5+
@version "3.13.0"
66

77
def project do
88
[

mix.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
%{
22
"decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"},
3-
"earmark_parser": {:hex, :earmark_parser, "1.4.43", "34b2f401fe473080e39ff2b90feb8ddfeef7639f8ee0bbf71bb41911831d77c5", [:mix], [], "hexpm", "970a3cd19503f5e8e527a190662be2cee5d98eed1ff72ed9b3d1a3d466692de8"},
4-
"ex_doc": {:hex, :ex_doc, "0.37.2", "2a3aa7014094f0e4e286a82aa5194a34dd17057160988b8509b15aa6c292720c", [:mix], [{:earmark_parser, "~> 1.4.42", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "4dfa56075ce4887e4e8b1dcc121cd5fcb0f02b00391fd367ff5336d98fa49049"},
3+
"earmark_parser": {:hex, :earmark_parser, "1.4.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"},
4+
"ex_doc": {:hex, :ex_doc, "0.38.2", "504d25eef296b4dec3b8e33e810bc8b5344d565998cd83914ffe1b8503737c02", [:mix], [{:earmark_parser, "~> 1.4.44", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "732f2d972e42c116a70802f9898c51b54916e542cc50968ac6980512ec90f42b"},
55
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
66
"makeup": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"},
77
"makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"},

0 commit comments

Comments
 (0)