lib/baz/settings/settings_store.ex

defmodule Baz.Settings.SettingsStore do
  use GenServer

  @type store_id :: atom
  @type key :: atom
  @type value :: term

  @default_id :default
  @table_name :settings_store

  @spec start_link(keyword) :: GenServer.on_start()
  def start_link(args) do
    id = Keyword.get(args, :id, @default_id)
    name = process_name(id)

    GenServer.start_link(__MODULE__, [], name: name)
  end

  @spec process_name(store_id) :: atom
  def process_name(store_id), do: :"#{__MODULE__}_#{store_id}"

  @spec put(key, value) :: {:ok, {key, value}}
  def put(key, value, store_id \\ @default_id) do
    store_id
    |> process_name()
    |> GenServer.call({:put, key, value})
  end

  @type find_result :: {:ok, value} | {:error, :not_found}

  @spec find(key) :: find_result
  def find(key, _store_id \\ @default_id) do
    @table_name
    |> :ets.lookup(key)
    |> case do
      [{_, value} | _] -> {:ok, value}
      [] -> {:error, :not_found}
    end
  end

  @type all_result :: [{key, value}]

  @spec all :: all_result
  def all(_store_id \\ @default_id) do
    @table_name
    |> :ets.tab2list()
  end

  @impl true
  def init(state) do
    :ets.new(@table_name, [:set, :protected, :named_table])
    {:ok, state}
  end

  @impl true
  def handle_call({:put, key, value}, _from, state) do
    record = {key, value}
    true = :ets.insert(@table_name, record)
    {:reply, {:ok, record}, state}
  end
end