Files
bDS2/lib/bds/map_utils.ex
2026-05-10 11:30:08 +02:00

58 lines
1.7 KiB
Elixir

defmodule BDS.MapUtils do
@moduledoc """
Utility functions for working with maps that may have atom or string keys,
including safe atom conversion for untrusted input.
"""
@typedoc "An attribute map that may use atom or string keys."
@type attrs :: %{optional(atom()) => term(), optional(String.t()) => term()}
@spec attr(attrs(), atom()) :: term()
def attr(attrs, key) do
cond do
Map.has_key?(attrs, key) -> Map.get(attrs, key)
Map.has_key?(attrs, Atom.to_string(key)) -> Map.get(attrs, Atom.to_string(key))
true -> nil
end
end
@spec attr(attrs(), atom(), term()) :: term()
def attr(attrs, key, default) do
cond do
Map.has_key?(attrs, key) -> Map.get(attrs, key)
Map.has_key?(attrs, Atom.to_string(key)) -> Map.get(attrs, Atom.to_string(key))
true -> default
end
end
@spec maybe_put(map(), term(), term()) :: map()
def maybe_put(map, _key, nil), do: map
def maybe_put(map, key, value), do: Map.put(map, key, value)
@spec blank_to_nil(term()) :: term()
def blank_to_nil(nil), do: nil
def blank_to_nil(""), do: nil
def blank_to_nil(value), do: value
@spec safe_atomize_key(atom() | String.t()) :: atom() | String.t()
def safe_atomize_key(key) when is_atom(key), do: key
def safe_atomize_key(key) when is_binary(key) do
String.to_existing_atom(key)
rescue
ArgumentError -> key
end
@spec safe_atomize_keys(term()) :: term()
def safe_atomize_keys(value) when is_map(value) do
value
|> Enum.map(fn {key, nested_value} ->
{safe_atomize_key(key), safe_atomize_keys(nested_value)}
end)
|> Map.new()
end
def safe_atomize_keys(value) when is_list(value), do: Enum.map(value, &safe_atomize_keys/1)
def safe_atomize_keys(value), do: value
end