cover/Elixir.WalletNotifications.PreferenceStore.html

1 defmodule WalletNotifications.PreferenceStore do
2 @moduledoc """
3 ETS-backed GenServer for user notification preferences.
4
5 Table: `:wallet_notif_preferences` — keyed by {user_id, channel}.
6 """
7 use GenServer
8
9 alias WalletNotifications.Preference
10
11 @table :wallet_notif_preferences
12
13
:-(
def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)
14
15 @spec upsert(Preference.t()) :: :ok
16 11 def upsert(%Preference{} = pref), do: GenServer.call(__MODULE__, {:upsert, pref})
17
18 @spec get(user_id :: String.t(), channel :: atom()) :: {:ok, Preference.t()} | {:error, :not_found}
19 22 def get(user_id, channel), do: GenServer.call(__MODULE__, {:get, user_id, channel})
20
21 @spec list_by_user(String.t()) :: [Preference.t()]
22 2 def list_by_user(user_id), do: GenServer.call(__MODULE__, {:list_by_user, user_id})
23
24 14 def reset, do: GenServer.call(__MODULE__, :reset)
25
26 @impl true
27 def init(_) do
28
:-(
:ets.new(@table, [:set, :protected, :named_table])
29 {:ok, %{}}
30 end
31
32 @impl true
33 def handle_call({:upsert, pref}, _from, state) do
34 11 :ets.insert(@table, {{pref.user_id, pref.channel}, pref})
35 11 {:reply, :ok, state}
36 end
37
38 @impl true
39 def handle_call({:get, user_id, channel}, _from, state) do
40 22 result = case :ets.lookup(@table, {user_id, channel}) do
41 7 [{_, p}] -> {:ok, p}
42 15 [] -> {:error, :not_found}
43 end
44 22 {:reply, result, state}
45 end
46
47 @impl true
48 def handle_call({:list_by_user, user_id}, _from, state) do
49 2 prefs = :ets.tab2list(@table)
50 3 |> Enum.map(fn {_, p} -> p end)
51 3 |> Enum.filter(&(&1.user_id == user_id))
52 2 {:reply, prefs, state}
53 end
54
55 @impl true
56 def handle_call(:reset, _from, state) do
57 14 :ets.delete_all_objects(@table)
58 14 {:reply, :ok, state}
59 end
60 end
Line Hits Source