Skip to content

Commit 80a4459

Browse files
committed
feat: add ets & dets function that are useful
1 parent df6f009 commit 80a4459

File tree

5 files changed

+645
-1
lines changed

5 files changed

+645
-1
lines changed

lib/cache/dets.ex

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,170 @@ defmodule Cache.DETS do
3030

3131
@behaviour Cache
3232

33+
defmacro __using__(_opts) do
34+
quote do
35+
@doc """
36+
Match objects in the DETS table that match the given pattern.
37+
38+
## Examples
39+
40+
iex> #{inspect(__MODULE__)}.match_object({:_, :_})
41+
[...]
42+
"""
43+
def match_object(pattern) do
44+
:dets.match_object(@cache_name, pattern)
45+
end
46+
47+
@doc """
48+
Match objects in the DETS table that match the given pattern with limit.
49+
50+
## Examples
51+
52+
iex> #{inspect(__MODULE__)}.match_object({:_, :_}, 10)
53+
{[...], continuation}
54+
"""
55+
def match_object(pattern, limit) do
56+
:dets.match_object(@cache_name, pattern, limit)
57+
end
58+
59+
@doc """
60+
Check if a key is a member of the DETS table.
61+
62+
## Examples
63+
64+
iex> #{inspect(__MODULE__)}.member(:key)
65+
true
66+
"""
67+
def member(key) do
68+
:dets.member(@cache_name, key)
69+
end
70+
71+
@doc """
72+
Select objects from the DETS table using a match specification.
73+
74+
## Examples
75+
76+
iex> #{inspect(__MODULE__)}.select([{{:key, :_}, [], [:'$_']}])
77+
[...]
78+
"""
79+
def select(match_spec) do
80+
:dets.select(@cache_name, match_spec)
81+
end
82+
83+
@doc """
84+
Select objects from the DETS table using a match specification with limit.
85+
86+
## Examples
87+
88+
iex> #{inspect(__MODULE__)}.select([{{:key, :_}, [], [:'$_']}], 10)
89+
{[...], continuation}
90+
"""
91+
def select(match_spec, limit) do
92+
:dets.select(@cache_name, match_spec, limit)
93+
end
94+
95+
@doc """
96+
Get information about the DETS table.
97+
98+
## Examples
99+
100+
iex> #{inspect(__MODULE__)}.info()
101+
[...]
102+
"""
103+
def info() do
104+
:dets.info(@cache_name)
105+
end
106+
107+
@doc """
108+
Get specific information about the DETS table.
109+
110+
## Examples
111+
112+
iex> #{inspect(__MODULE__)}.info(:size)
113+
42
114+
"""
115+
def info(item) do
116+
:dets.info(@cache_name, item)
117+
end
118+
119+
@doc """
120+
Delete objects from the DETS table using a match specification.
121+
122+
## Examples
123+
124+
iex> #{inspect(__MODULE__)}.select_delete([{{:key, :_}, [], [true]}])
125+
42
126+
"""
127+
def select_delete(match_spec) do
128+
:dets.select_delete(@cache_name, match_spec)
129+
end
130+
131+
@doc """
132+
Delete objects from the DETS table that match the given pattern.
133+
134+
## Examples
135+
136+
iex> #{inspect(__MODULE__)}.match_delete({:key, :_})
137+
:ok
138+
"""
139+
def match_delete(pattern) do
140+
:dets.match_delete(@cache_name, pattern)
141+
end
142+
143+
@doc """
144+
Update a counter in the DETS table.
145+
146+
## Examples
147+
148+
iex> #{inspect(__MODULE__)}.update_counter(:counter_key, {2, 1})
149+
43
150+
"""
151+
def update_counter(key, update_op) do
152+
:dets.update_counter(@cache_name, key, update_op)
153+
end
154+
155+
@doc """
156+
Insert raw data into the DETS table using the underlying :dets.insert/2 function.
157+
158+
## Examples
159+
160+
iex> #{inspect(__MODULE__)}.insert_raw({:key, "value"})
161+
:ok
162+
iex> #{inspect(__MODULE__)}.insert_raw([{:key1, "value1"}, {:key2, "value2"}])
163+
:ok
164+
"""
165+
def insert_raw(data) do
166+
:dets.insert(@cache_name, data)
167+
end
168+
169+
if function_exported?(:dets, :to_ets, 1) do
170+
@doc """
171+
Convert a DETS table to an ETS table.
172+
173+
## Examples
174+
175+
iex> #{inspect(__MODULE__)}.to_ets()
176+
:my_ets_table
177+
"""
178+
def to_ets() do
179+
:dets.to_ets(@cache_name)
180+
end
181+
182+
@doc """
183+
Convert an ETS table to a DETS table.
184+
185+
## Examples
186+
187+
iex> #{inspect(__MODULE__)}.from_ets(:my_ets_table)
188+
:ok
189+
"""
190+
def from_ets(ets_table) do
191+
:dets.from_ets(@cache_name, ets_table)
192+
end
193+
end
194+
end
195+
end
196+
33197
@impl Cache
34198
def opts_definition, do: @opts_definition
35199

@@ -74,6 +238,8 @@ defmodule Cache.DETS do
74238
def get(cache_name, key, _opts \\ []) do
75239
case :dets.lookup(cache_name, key) do
76240
[{^key, value}] -> {:ok, value}
241+
# This can happen if someone uses insert_raw
242+
[value] -> {:ok, value}
77243
[] -> {:ok, nil}
78244
end
79245
end

lib/cache/ets.ex

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,170 @@ defmodule Cache.ETS do
3838

3939
@behaviour Cache
4040

41+
defmacro __using__(_opts) do
42+
quote do
43+
@doc """
44+
Match objects in the ETS table that match the given pattern.
45+
46+
## Examples
47+
48+
iex> #{inspect(__MODULE__)}.match_object({:_, :_})
49+
[...]
50+
"""
51+
def match_object(pattern) do
52+
:ets.match_object(@cache_name, pattern)
53+
end
54+
55+
@doc """
56+
Match objects in the ETS table that match the given pattern with limit.
57+
58+
## Examples
59+
60+
iex> #{inspect(__MODULE__)}.match_object({:_, :_}, 10)
61+
{[...], continuation}
62+
"""
63+
def match_object(pattern, limit) do
64+
:ets.match_object(@cache_name, pattern, limit)
65+
end
66+
67+
@doc """
68+
Check if a key is a member of the ETS table.
69+
70+
## Examples
71+
72+
iex> #{inspect(__MODULE__)}.member(:key)
73+
true
74+
"""
75+
def member(key) do
76+
:ets.member(@cache_name, key)
77+
end
78+
79+
@doc """
80+
Select objects from the ETS table using a match specification.
81+
82+
## Examples
83+
84+
iex> #{inspect(__MODULE__)}.select([{{:key, :_}, [], [:'$_']}])
85+
[...]
86+
"""
87+
def select(match_spec) do
88+
:ets.select(@cache_name, match_spec)
89+
end
90+
91+
@doc """
92+
Select objects from the ETS table using a match specification with limit.
93+
94+
## Examples
95+
96+
iex> #{inspect(__MODULE__)}.select([{{:key, :_}, [], [:'$_']}], 10)
97+
{[...], continuation}
98+
"""
99+
def select(match_spec, limit) do
100+
:ets.select(@cache_name, match_spec, limit)
101+
end
102+
103+
@doc """
104+
Get information about the ETS table.
105+
106+
## Examples
107+
108+
iex> #{inspect(__MODULE__)}.info()
109+
[...]
110+
"""
111+
def info() do
112+
:ets.info(@cache_name)
113+
end
114+
115+
@doc """
116+
Get specific information about the ETS table.
117+
118+
## Examples
119+
120+
iex> #{inspect(__MODULE__)}.info(:size)
121+
42
122+
"""
123+
def info(item) do
124+
:ets.info(@cache_name, item)
125+
end
126+
127+
@doc """
128+
Delete objects from the ETS table using a match specification.
129+
130+
## Examples
131+
132+
iex> #{inspect(__MODULE__)}.select_delete([{{:key, :_}, [], [true]}])
133+
42
134+
"""
135+
def select_delete(match_spec) do
136+
:ets.select_delete(@cache_name, match_spec)
137+
end
138+
139+
@doc """
140+
Delete objects from the ETS table that match the given pattern.
141+
142+
## Examples
143+
144+
iex> #{inspect(__MODULE__)}.match_delete({:key, :_})
145+
true
146+
"""
147+
def match_delete(pattern) do
148+
:ets.match_delete(@cache_name, pattern)
149+
end
150+
151+
@doc """
152+
Update a counter in the ETS table.
153+
154+
## Examples
155+
156+
iex> #{inspect(__MODULE__)}.update_counter(:counter_key, {2, 1})
157+
43
158+
"""
159+
def update_counter(key, update_op) do
160+
:ets.update_counter(@cache_name, key, update_op)
161+
end
162+
163+
@doc """
164+
Insert raw data into the ETS table using the underlying :ets.insert/2 function.
165+
166+
## Examples
167+
168+
iex> #{inspect(__MODULE__)}.insert_raw({:key, "value"})
169+
true
170+
iex> #{inspect(__MODULE__)}.insert_raw([{:key1, "value1"}, {:key2, "value2"}])
171+
true
172+
"""
173+
def insert_raw(data) do
174+
:ets.insert(@cache_name, data)
175+
end
176+
177+
if function_exported?(:ets, :to_dets, 1) do
178+
@doc """
179+
Convert an ETS table to a DETS table.
180+
181+
## Examples
182+
183+
iex> #{inspect(__MODULE__)}.to_dets(:my_dets_table)
184+
:ok
185+
"""
186+
def to_dets(dets_table) do
187+
:ets.to_dets(@cache_name, dets_table)
188+
end
189+
190+
@doc """
191+
Convert a DETS table to an ETS table.
192+
193+
## Examples
194+
195+
iex> #{inspect(__MODULE__)}.from_dets(:my_dets_table)
196+
:ok
197+
"""
198+
def from_dets(dets_table) do
199+
:ets.from_dets(@cache_name, dets_table)
200+
end
201+
end
202+
end
203+
end
204+
41205
@impl Cache
42206
def opts_definition, do: @opts_definition
43207

@@ -76,6 +240,8 @@ defmodule Cache.ETS do
76240
def get(cache_name, key, _opts \\ []) do
77241
case :ets.lookup(cache_name, key) do
78242
[{^key, value}] -> {:ok, value}
243+
# This can happen if someone uses insert_raw
244+
[value] -> {:ok, value}
79245
[] -> {:ok, nil}
80246
end
81247
end

lib/cache/metrics.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ if Application.ensure_loaded(:prometheus_telemetry) === :ok do
104104
metadata
105105
|> Map.take([:error, :cache_name])
106106
|> Map.update(:error, "unknown", fn
107-
%ErrorMessage{code: code, message: error} -> "code}: #{error}"
107+
%ErrorMessage{code: code, message: error} -> "#{code}: #{error}"
108108
reason when is_atom(reason) -> to_string(reason)
109109
reason when is_binary(reason) -> reason
110110
_ -> "unknown"

0 commit comments

Comments
 (0)