Current section
Files
Jump to
Current section
Files
lib/gen_ets.ex
defmodule GenETS do
use GenServer
alias :ets, as: ETS
require Logger
@type key() :: any()
@type value() :: any()
@type key_value() :: {key(), value()}
@doc """
Starts a GenETS process without links.
See `start_link/1` for more information
"""
def start(args \\ []) do
args = prepare_args(args)
server_name = server_name(args.table_name)
GenServer.start(__MODULE__, args, name: server_name)
end
@doc """
Starts a GenETS process linked to the current process.
# Start a new GenETS:
iex(1)> {:ok, pid} = GenETS.start(table_name: :some_table_name)
{:ok, #PID<0.140.0>}
# Control using the provided PID:
iex(2)> GenETS.write(pid, :key, :value)
:ok
# Alternatively, you can use your table_name as well:
iex(3)> GenETS.read(:some_table_name, :key)
[key: :value]
"""
def start_link(args \\ []) do
args = prepare_args(args)
server_name = server_name(args.table_name)
GenServer.start_link(__MODULE__, args, name: server_name)
end
@spec exists?(ETS.table(), key()) :: boolean()
def direct_exists?(table, key) do
case ETS.lookup(table, key) do
[_ | _] -> true
_ -> false
end
end
@spec direct_delete(ETS.table(), key()) :: :ok
def direct_delete(table, key) do
true = ETS.delete(table, key)
:ok
end
@spec direct_write(ETS.table(), key(), value()) :: :ok
def direct_write(table, key, value) do
true = ETS.insert(table, {key, value})
:ok
end
@spec direct_read(ETS.table(), key()) :: [key_value()]
def direct_read(table, key) do
ETS.lookup(table, key)
end
@spec direct_prune(ETS.table()) :: :ok
def direct_prune(table) do
true = ETS.delete_all_objects(table)
:ok
end
@spec prune(ETS.table() | pid()) :: :ok
def prune(pid) when is_pid(pid) do
GenServer.call(pid, :prune)
end
def prune(table_name) do
GenServer.call(server_name(table_name), :prune)
end
@spec read(ETS.table() | pid(), key()) :: [key_value()]
def read(pid, key) when is_pid(pid) do
GenServer.call(pid, {:read, key})
end
def read(table_name, key) do
GenServer.call(server_name(table_name), {:read, key})
end
@spec write(ETS.table() | pid(), key(), value()) :: :ok
def write(pid, key, value) when is_pid(pid) do
GenServer.call(pid, {:write, key, value})
end
def write(table_name, key, value) do
GenServer.call(server_name(table_name), {:write, key, value})
end
@spec delete(ETS.table() | pid(), key()) :: :ok
def delete(pid, key) when is_pid(pid) do
GenServer.call(pid, {:delete, key})
end
def delete(table_name, key) do
GenServer.call(server_name(table_name), {:delete, key})
end
@spec exists?(ETS.table() | pid(), key()) :: boolean()
def exists?(pid, key) when is_pid(pid) do
GenServer.call(pid, {:exists?, key})
end
def exists?(table_name, key) do
GenServer.call(server_name(table_name), {:exists?, key})
end
@impl true
def init(args) do
%{table_name: table_name, table_args: table_args} = args
table_ref = ETS.new(table_name, table_args)
state = %{
table_name: table_name,
table_ref: table_ref
}
{:ok, state}
end
@impl true
def handle_call({:read, key}, _from, state) do
result = direct_read(state.table_ref, key)
{:reply, result, state}
end
@impl true
def handle_call({:write, key, value}, _from, state) do
:ok = direct_write(state.table_ref, key, value)
{:reply, :ok, state}
end
@impl true
def handle_call({:delete, key}, _from, state) do
:ok = direct_delete(state.table_ref, key)
{:reply, :ok, state}
end
@impl true
def handle_call({:exists?, key}, _from, state) do
result = direct_exists?(state.table_ref, key)
{:reply, result, state}
end
@impl true
def handle_call(:prune, _from, state) do
:ok = direct_prune(state.table_ref)
{:reply, :ok, state}
end
@impl true
def handle_call(message, _from, state) do
Logger.warning("Got unknown call message: #{inspect(message)}")
{:reply, {:error, :badarg}, state}
end
@impl true
def handle_cast(message, state) do
Logger.warning("Got unknown cast message: #{inspect(message)}")
{:noreply, state}
end
@impl true
def handle_info(message, state) do
Logger.warning("Got unknown info message: #{inspect(message)}")
{:noreply, state}
end
defp server_name(table_name), do: :"GenETS.#{table_name}"
defp prepare_args(args) do
%{
table_name: Keyword.get(args, :table_name, nil),
table_args: Keyword.get(args, :table_args, [:set])
}
end
end