What a transition's commit needs from the datastore.
Three operations: a transaction serialised per record, a preloaded read
under it, and the status write. An Ecto.Repo satisfies update/1 as is
and needs the other two added:
defmodule MyApp.Repo do
use Ecto.Repo, otp_app: :my_app, adapter: Ecto.Adapters.Postgres
@behaviour Hoare.Store
@impl Hoare.Store
def transact_with_lock(lock, fun) do
transact(fn ->
query!("SELECT pg_advisory_xact_lock($1)", [:erlang.phash2(lock)])
fun.()
end)
end
@impl Hoare.Store
def read(schema, id, preloads) do
if record = get(schema, id),
do: {:ok, preload(record, preloads)},
else: {:error, :not_found}
end
endThe record's schema supplies changeset/2, which update/1 receives with the
new status. Hoare.Store.Memory is the store for tests.
Summary
Callbacks
Reads the record by id with preloads loaded, inside the caller's transaction.
Runs fun inside a transaction that no other holder of lock shares; its result is the return.