Files
wanderer/lib/wanderer_app/cache.ex
2025-11-29 12:34:28 +01:00

147 lines
4.0 KiB
Elixir

defmodule WandererApp.Cache do
@moduledoc false
use Nebulex.Cache,
otp_app: :wanderer_app,
adapter: Nebulex.Adapters.Local
require Logger
def lookup(key, default \\ nil)
def lookup({id, key}, default) when is_binary(id) and (is_binary(key) or is_atom(key)),
do: lookup("#{id}:#{key}", default)
def lookup(key, default) when is_binary(key) or is_atom(key) do
case get(key) do
nil -> {:ok, default}
value -> {:ok, value}
end
end
def lookup!(key, default \\ nil)
def lookup!({id, key}, default) when is_binary(id) and (is_binary(key) or is_atom(key)),
do: lookup!("#{id}:#{key}", default)
def lookup!(key, default) when is_binary(key) or is_atom(key) do
{:ok, result} = lookup(key, default)
result
end
def get_and_remove(key, default) when is_binary(key) or is_atom(key) do
case take(key) do
nil -> {:ok, default}
value -> {:ok, value}
end
end
def get_and_remove!(key, default) when is_binary(key) or is_atom(key) do
{:ok, result} = get_and_remove(key, default)
result
end
def insert(key, value, opts \\ [])
def insert({id, key}, value, opts) when is_binary(id) and (is_binary(key) or is_atom(key)),
do: insert("#{id}:#{key}", value, opts)
def insert(key, nil, _opts) when is_binary(key) or is_atom(key), do: delete(key)
def insert(key, value, opts) when is_binary(key) or is_atom(key), do: put(key, value, opts)
def insert_or_update(key, value, update_fn, opts \\ [])
def insert_or_update({id, key}, value, update_fn, opts)
when is_binary(id) and (is_binary(key) or is_atom(key)),
do: insert_or_update("#{id}:#{key}", value, update_fn, opts)
def insert_or_update(key, value, update_fn, opts) when is_binary(key) or is_atom(key) do
case lookup(key) do
{:ok, nil} ->
insert(key, value, opts)
{:ok, data} ->
insert(key, update_fn.(data), opts)
end
end
def find_by_attrs(type, attrs, match \\ :any) do
case type |> get() |> find(attrs, match: match) do
%{} = item -> {:ok, item}
nil -> {:error, :item_not_found}
end
end
def filter_by_attr_in(type, attr, includes), do: type |> get() |> filter_in(attr, includes)
@doc """
Batch lookup multiple keys from cache.
Returns a map of key => value pairs, with `default` used for missing keys.
"""
def lookup_all(keys, default \\ nil) when is_list(keys) do
# Get all values from cache
values = get_all(keys)
# Build result map with defaults for missing keys
result =
keys
|> Enum.map(fn key ->
value = Map.get(values, key, default)
{key, value}
end)
|> Map.new()
{:ok, result}
end
@doc """
Batch insert multiple key-value pairs into cache.
Accepts a map of key => value pairs or a list of {key, value} tuples.
Skips nil values (deletes the key instead).
"""
def insert_all(entries, opts \\ [])
def insert_all(entries, opts) when is_map(entries) do
# Filter out nil values and delete those keys
{to_delete, to_insert} =
entries
|> Enum.split_with(fn {_key, value} -> is_nil(value) end)
# Delete keys with nil values
Enum.each(to_delete, fn {key, _} -> delete(key) end)
# Insert non-nil values
unless Enum.empty?(to_insert) do
put_all(to_insert, opts)
end
:ok
end
def insert_all(entries, opts) when is_list(entries) do
insert_all(Map.new(entries), opts)
end
defp find(list, %{} = attrs, match: match) do
list
|> Enum.find(fn item ->
case match do
:any -> Enum.any?(attrs, &has_equal_attribute?(item, &1))
:all -> Enum.all?(attrs, &has_equal_attribute?(item, &1))
end
end)
end
defp filter_in(nil, _attr, _includes), do: []
defp filter_in(list, attr, includes),
do:
list
|> Enum.filter(&(&1[attr] in includes))
defp has_equal_attribute?(%{} = map, {key, {:case_insensitive, value}}) when is_binary(value) do
String.downcase(Map.get(map, key, "")) == String.downcase(value)
end
defp has_equal_attribute?(%{} = map, {key, value}), do: Map.get(map, key) == value
end