Current section
Files
Jump to
Current section
Files
lib/cachex/actions/get_and_update.ex
defmodule Cachex.Actions.GetAndUpdate do
@moduledoc false
# Command module to enable transactional get/update semantics.
#
# This command is simply sugar, but is common enough that it deserved an explicit
# implementation inside the API. It does take care of the transactional context
# of the get/update semantics though, so it's potentially non-obvious.
alias Cachex.Actions
alias Cachex.Services.Locksmith
# add needed imports
import Cachex.Spec
##############
# Public API #
##############
@doc """
Retrieves an entry and updates it inside the cache.
This is basically all sugar for `transaction -> set(fun(get()))` but it provides
an easy-to-use way to update a value directly in the cache. Naturally this
means that the key needs to be locked and so we use a transaction to provide
this guarantee.
If the key is not returned by the call to `:get`, then we have to set the new
value in the cache directly. If it does exist, then we use the update actions
to update the existing record.
"""
def execute(cache() = cache, key, update_fun, _options) do
Locksmith.transaction(cache, [key], fn ->
{_label, value} = Cachex.get(cache, key, [])
formatted =
value
|> update_fun.()
|> Actions.format_fetch_value()
operation = Actions.write_op(value)
normalized = Actions.normalize_commit(formatted)
with {:commit, new_value, options} <- normalized do
apply(Cachex, operation, [cache, key, new_value, options])
{:commit, new_value}
end
end)
end
end