From a5b0f98f5b74f6d5a8052ef41706f3d38d5a6a27 Mon Sep 17 00:00:00 2001 From: Henry Zhan Date: Wed, 18 Mar 2026 09:55:49 -0500 Subject: [PATCH] Document {:unsafe_fragment, fragment} option for :returning Add documentation for the new {:unsafe_fragment, fragment} tuple format that can be passed to the :returning option. This allows raw SQL expressions to be used in the RETURNING clause for PostgreSQL and OUTPUT clause for MSSQL. --- lib/ecto/repo.ex | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/lib/ecto/repo.ex b/lib/ecto/repo.ex index 8af8e3014e..6a5ad7c8ec 100644 --- a/lib/ecto/repo.ex +++ b/lib/ecto/repo.ex @@ -1655,6 +1655,8 @@ defmodule Ecto.Repo do returns all fields in the given schema. May be a list of fields, where a struct is still returned but only with the given fields. Or `false`, where nothing is returned (the default). + It also accepts `{:unsafe_fragment, fragment}` to pass a raw SQL + expression directly to the RETURNING clause (not escaped, use with caution). This option is not supported by all databases. * `:prefix` - The prefix to run the query on (such as the schema path @@ -1822,8 +1824,10 @@ defmodule Ecto.Repo do of fields to be returned from the database. When `true`, returns all fields, including those marked as `load_in_query: false`. When `false`, no extra fields are returned. It will always include all - fields in `read_after_writes` as well as any autogenerated id. Be - aware that the fields returned from the database overwrite what was + fields in `read_after_writes` as well as any autogenerated id. + It also accepts `{:unsafe_fragment, fragment}` to pass a raw SQL + expression directly to the RETURNING clause (not escaped, use with caution). + Be aware that the fields returned from the database overwrite what was supplied by the user. Any field not returned by the database will be present with the original value supplied by the user. Not all databases support this option and it may not be available during upserts. @@ -2040,10 +2044,12 @@ defmodule Ecto.Repo do of fields to be returned from the database. When `true`, returns all fields, including those marked as `load_in_query: false`. When `false`, no extra fields are returned. It will always include all - fields in `read_after_writes`. Be aware that the fields returned - from the database overwrite what was supplied by the user. Any field - not returned by the database will be present with the original value - supplied by the user. Not all databases support this option. + fields in `read_after_writes`. It also accepts `{:unsafe_fragment, fragment}` + to pass a raw SQL expression directly to the RETURNING clause (not escaped, + use with caution). Be aware that the fields returned from the database + overwrite what was supplied by the user. Any field not returned by the + database will be present with the original value supplied by the user. + Not all databases support this option. * `:force` - By default, if there are no changes in the changeset, `c:update/2` is a no-op. By setting this option to true, update @@ -2158,10 +2164,12 @@ defmodule Ecto.Repo do of fields to be returned from the database. When `true`, returns all fields, including those marked as `load_in_query: false`. When `false`, no extra fields are returned. It will always include all - fields in `read_after_writes`. Be aware that the fields returned - from the database overwrite what was supplied by the user. Any field - not returned by the database will be present with the original value - supplied by the user. Not all databases support this option. + fields in `read_after_writes`. It also accepts `{:unsafe_fragment, fragment}` + to pass a raw SQL expression directly to the RETURNING clause (not escaped, + use with caution). Be aware that the fields returned from the database + overwrite what was supplied by the user. Any field not returned by the + database will be present with the original value supplied by the user. + Not all databases support this option. * `:prefix` - The prefix to run the query on (such as the schema path in Postgres or the database in MySQL). This overrides the prefix set