Current section

Files

Jump to
etso lib etso adapter table_registry.ex
Raw

lib/etso/adapter/table_registry.ex

defmodule Etso.Adapter.TableRegistry do
@moduledoc """
Provides convenience function to spin up a Registry, which is used to hold the Table Servers
(registered by GenServer when starting up), alongside their ETS tables (registered when the
Table Server starts).
"""
@spec child_spec(Etso.repo()) :: Supervisor.child_spec()
@spec get_table(Etso.repo(), Etso.schema()) :: {:ok, Etso.table()} | {:error, term()}
@spec register_table(Etso.repo(), Etso.schema(), Etso.table()) :: :ok | {:error, term()}
alias Etso.Adapter.TableServer
alias Etso.Adapter.TableSupervisor
@doc """
Returns Child Specification for the Table Registry that will be associated with the `repo`.
"""
def child_spec(repo) do
Registry.child_spec(keys: :unique, name: build_name(repo))
end
@doc """
Returns the ETS table associated with the given `repo` which is used to hold data for `schema`.
"""
def get_table(repo, schema) do
case lookup_table(repo, schema) do
{:ok, table_reference} -> {:ok, table_reference}
{:error, :not_found} -> start_table(repo, schema)
end
end
@doc """
Registers the ETS table associated with the given `repo` which is used to hold data for `schema`.
"""
def register_table(repo, schema, table_reference) do
with {:ok, _} <- Registry.register(build_name(repo), {schema, :ets_table}, table_reference) do
:ok
end
end
defp lookup_table(repo, schema) do
case Registry.lookup(build_name(repo), {schema, :ets_table}) do
[{_, table_reference}] -> {:ok, table_reference}
[] -> {:error, :not_found}
end
end
defp start_table(repo, schema) do
with {:ok, _} <- ensure_server_started(repo, schema) do
lookup_table(repo, schema)
end
end
defp ensure_server_started(repo, schema) do
case start_server(repo, schema) do
{:ok, pid} -> {:ok, pid}
{:ok, pid, _} -> {:ok, pid}
{:error, {:already_started, pid}} -> {:ok, pid}
_ -> :error
end
end
defp start_server(repo, schema) do
name = {:via, Registry, {build_name(repo), schema}}
child_spec = {TableServer, {repo, schema, name}}
TableSupervisor.start_child(repo, child_spec)
end
defp build_name(repo) do
Module.concat([repo, Enum.at(Module.split(__MODULE__), -1)])
end
end