$ iex -S mix
Erlang/OTP 22 [erts-10.5.3] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe] [dtrace]
Interactive Elixir (1.9.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> alias Friends.{Repo,Person}
[Friends.Repo, Friends.Person]
iex(2)> import Ecto.Query
Ecto.Query
iex(3)> query = from(Person, where: [id: 1])
#Ecto.Query<from p0 in Friends.Person, where: p0.id == 1>
iex(4)> update = from(query, update: [inc: [age: +1]])
#Ecto.Query<from p0 in Friends.Person, where: p0.id == 1,
update: [inc: [age: 1]]>
iex(5)> multi = Ecto.Multi.new() |> Ecto.Multi.update_all(:birthday, update, [])
%Ecto.Multi{
names: #MapSet<[:birthday]>,
operations: [
birthday: {:update_all,
#Ecto.Query<from p0 in Friends.Person, where: p0.id == 1,
update: [inc: [age: 1]]>, [], []}
]
}
iex(6)> Repo.all(query)
16:23:51.903 [debug] QUERY OK source="people" db=0.7ms decode=0.6ms queue=1.0ms
SELECT p0."id", p0."first_name", p0."last_name", p0."age" FROM "people" AS p0 WHERE (p0."id" = 1) []
[
%Friends.Person{
__meta__: #Ecto.Schema.Metadata<:loaded, "people">,
age: 30,
first_name: "Ryan",
id: 1,
last_name: "Bigg"
}
]
iex(7)> Repo.transaction(multi)
16:23:51.908 [debug] QUERY OK db=0.3ms
begin []
16:23:51.910 [debug] QUERY OK source="people" db=0.7ms
UPDATE "people" AS p0 SET "age" = p0."age" + 1 WHERE (p0."id" = 1) []
16:23:51.916 [debug] QUERY OK db=6.2ms
commit []
{:ok, %{birthday: {1, nil}}}
iex(8)> Repo.all(query)
16:23:51.919 [debug] QUERY OK source="people" db=2.3ms
SELECT p0."id", p0."first_name", p0."last_name", p0."age" FROM "people" AS p0 WHERE (p0."id" = 1) []
[
%Friends.Person{
__meta__: #Ecto.Schema.Metadata<:loaded, "people">,
age: 31,
first_name: "Ryan",
id: 1,
last_name: "Bigg"
}
]
iex(9)>
So
multi = Ecto.Multi.new() |> Ecto.Multi.update_all(:john_birthday, john_update, [])
should fix your example. Your queryable
already contains the updates - so the updates
argument needs to be an empty list (the opts
argument defaults to an empty list).
# file: friends/priv/repo/playground.exs
#
# pg_ctl -D /usr/local/var/postgres start
# mix format ./priv/repo/playground.exs
# mix run ./priv/repo/playground.exs
#
defmodule AppInfo do
def string() do
Application.loaded_applications()
|> Enum.map(&to_app_keyword/1)
|> Enum.sort_by(&map_app_name/1)
|> Enum.map_join(", ", &app_keyword_to_string/1)
end
defp to_app_keyword({app, _, vsn}),
do: {app, vsn}
defp app_keyword_to_string({app, vsn}),
do: "#{app}: #{vsn}"
defp map_app_name({app, _}),
do: app
end
defmodule Playground do
import Ecto.Query
alias Ecto.Multi, as: EM
alias Friends.{Repo, Person}
def play do
query = from(p in Person, where: p.id == 1)
update = query |> update([p], inc: [age: 1])
multi =
EM.new()
|> EM.update_all(:birthday, update, [])
r0 = Repo.one(query)
r1 = Repo.transaction(multi)
r2 = Repo.one(query)
[r0: r0, r1: r1, r2: r2]
end
end
IO.puts(AppInfo.string())
IO.puts("#{inspect(Playground.play(), pretty: true)}")
$ mix run ./priv/repo/playground.exs
asn1: 5.0.9, compiler: 7.4.7, connection: 1.0.4, crypto: 4.6.1, db_connection: 2.1.1, decimal: 1.8.0, ecto: 3.2.3, ecto_sql: 3.2.0, elixir: 1.9.2, friends: 0.1.0, hex: 0.20.1, inets: 7.1.1, kernel: 6.5, logger: 1.9.2, mix: 1.9.2, postgrex: 0.15.1, public_key: 1.7, ssl: 9.4, stdlib: 3.10, telemetry: 0.4.0
18:46:51.903 [debug] QUERY OK source="people" db=0.6ms decode=0.6ms queue=0.8ms
SELECT p0."id", p0."first_name", p0."last_name", p0."age"
FROM "people" AS p0 WHERE (p0."id" = 1) []
18:46:51.907 [debug] QUERY OK db=0.2ms
begin []
18:46:51.909 [debug] QUERY OK source="people" db=0.8ms
UPDATE "people" AS p0 SET "age" = p0."age" + 1
WHERE (p0."id" = 1) []
18:46:51.915 [debug] QUERY OK db=6.2ms
commit []
18:46:51.918 [debug] QUERY OK source="people" db=2.6ms
SELECT p0."id", p0."first_name", p0."last_name", p0."age"
FROM "people" AS p0 WHERE (p0."id" = 1) []
[
r0: %Friends.Person{
__meta__: #Ecto.Schema.Metadata<:loaded, "people">,
age: 28,
first_name: "Ryan",
id: 1,
last_name: "Bigg"
},
r1: {:ok, %{birthday: {1, nil}}},
r2: %Friends.Person{
__meta__: #Ecto.Schema.Metadata<:loaded, "people">,
age: 29,
first_name: "Ryan",
id: 1,
last_name: "Bigg"
}
]
$