cover/Elixir.WalletRisk.RiskCaseStore.html

1 defmodule WalletRisk.RiskCaseStore do
2 @moduledoc """
3 ETS-backed GenServer for RiskCase persistence.
4
5 Tables:
6 - `:wallet_risk_cases` — keyed by case_id.
7 - `:wallet_risk_case_user_idx` — bag: {user_id, case_id}.
8 """
9
10 use GenServer
11
12 alias WalletRisk.RiskCase
13
14 @table :wallet_risk_cases
15 @user_idx :wallet_risk_case_user_idx
16
17
:-(
def start_link(opts), do: GenServer.start_link(__MODULE__, opts, name: __MODULE__)
18
19 @spec store(RiskCase.t()) :: :ok | {:error, :duplicate_case_id}
20 6 def store(%RiskCase{} = c), do: GenServer.call(__MODULE__, {:store, c})
21
22 @spec get(case_id :: String.t()) :: {:ok, RiskCase.t()} | {:error, :not_found}
23
:-(
def get(id), do: GenServer.call(__MODULE__, {:get, id})
24
25 @spec update(RiskCase.t()) :: :ok | {:error, :not_found}
26
:-(
def update(%RiskCase{} = c), do: GenServer.call(__MODULE__, {:update, c})
27
28 @spec list_by_user(user_id :: String.t()) :: [RiskCase.t()]
29 3 def list_by_user(uid), do: GenServer.call(__MODULE__, {:list_by_user, uid})
30
31 @spec list_all() :: [RiskCase.t()]
32
:-(
def list_all, do: GenServer.call(__MODULE__, :list_all)
33
34 @spec reset() :: :ok
35 29 def reset, do: GenServer.call(__MODULE__, :reset)
36
37 @impl true
38 def init(_opts) do
39
:-(
:ets.new(@table, [:set, :protected, :named_table])
40
:-(
:ets.new(@user_idx, [:bag, :protected, :named_table])
41 {:ok, %{}}
42 end
43
44 @impl true
45 def handle_call({:store, c}, _from, state) do
46 6 if :ets.member(@table, c.case_id) do
47
:-(
{:reply, {:error, :duplicate_case_id}, state}
48 else
49 6 :ets.insert(@table, {c.case_id, c})
50 6 :ets.insert(@user_idx, {c.user_id, c.case_id})
51 6 {:reply, :ok, state}
52 end
53 end
54
55 @impl true
56 def handle_call({:get, id}, _from, state) do
57
:-(
result =
58 case :ets.lookup(@table, id) do
59
:-(
[{_, c}] -> {:ok, c}
60
:-(
[] -> {:error, :not_found}
61 end
62
:-(
{:reply, result, state}
63 end
64
65 @impl true
66 def handle_call({:update, c}, _from, state) do
67
:-(
result =
68
:-(
case :ets.lookup(@table, c.case_id) do
69 [{_, _}] ->
70
:-(
:ets.insert(@table, {c.case_id, c})
71 :ok
72
:-(
[] ->
73 {:error, :not_found}
74 end
75
:-(
{:reply, result, state}
76 end
77
78 @impl true
79 def handle_call({:list_by_user, uid}, _from, state) do
80 3 ids = :ets.lookup(@user_idx, uid) |> Enum.map(fn {_, id} -> id end)
81 3 items =
82 Enum.flat_map(ids, fn id ->
83 2 case :ets.lookup(@table, id) do
84 2 [{_, c}] -> [c]
85
:-(
[] -> []
86 end
87 end)
88 3 {:reply, items, state}
89 end
90
91 @impl true
92 def handle_call(:list_all, _from, state) do
93
:-(
items = :ets.tab2list(@table) |> Enum.map(fn {_, c} -> c end)
94
:-(
{:reply, items, state}
95 end
96
97 @impl true
98 def handle_call(:reset, _from, state) do
99 29 :ets.delete_all_objects(@table)
100 29 :ets.delete_all_objects(@user_idx)
101 29 {:reply, :ok, state}
102 end
103 end
Line Hits Source