CubDB.get_and_update_multi
get_and_update_multi
, go back to CubDB module for more information.
Specs
get_and_update_multi( GenServer.server(), [key()], (%{optional(key()) => value()} -> {any(), %{optional(key()) => value()} | nil, [key()] | nil}), [opt] ) :: {:ok, any()} | {:error, any()} when opt: {:timeout, timeout()}
Gets and updates or deletes multiple entries in an atomic transaction.
Gets all values associated with keys in keys_to_get
, and passes them as a
map of %{key => value}
entries to fun
. If a key is not found, it won't be
added to the map passed to fun
. Updates the database and returns a result
according to the return value of fun
. Returns {:ok
, return_value} in case
of success, {:error, reason}
otherwise.
The function fun
should return a tuple of three elements: {return_value, entries_to_put, keys_to_delete}
, where return_value
is an arbitrary value
to be returned, entries_to_put
is a map of %{key => value}
entries to be
written to the database, and keys_to_delete
is a list of keys to be deleted.
The read and write operations are executed as an atomic transaction, so they
will either all succeed, or all fail. Note that get_and_update_multi/4
blocks other write operations until it completes.
The options
argument is an optional keyword list of options, including:
:timeout
- a timeout (in milliseconds or:infinity
, defaulting to5000
) for the operation, after which the function returns{:error, :timeout}
. This is useful to avoid blocking other write operations for too long.
Example
Assuming a database of names as keys, and integer monetary balances as values,
and we want to transfer 10 units from "Anna"
to "Joy"
, returning their
updated balance:
{:ok, {anna, joy}} = CubDB.get_and_update_multi(db, ["Anna", "Joy"], fn entries ->
anna = Map.get(entries, "Anna", 0)
joy = Map.get(entries, "Joy", 0)
if anna < 10, do: raise(RuntimeError, message: "Anna's balance is too low")
anna = anna - 10
joy = joy + 10
{{anna, joy}, %{"Anna" => anna, "Joy" => joy}, []}
end)
Or, if we want to transfer all of the balance from "Anna"
to "Joy"
,
deleting "Anna"
's entry, and returning "Joy"
's resulting balance:
{:ok, joy} = CubDB.get_and_update_multi(db, ["Anna", "Joy"], fn entries ->
anna = Map.get(entries, "Anna", 0)
joy = Map.get(entries, "Joy", 0)
joy = joy + anna
{joy, %{"Joy" => joy}, ["Anna"]}
end)