Packages
The typed, attribute-queryable in-memory store for ETS and Mnesia. A simple ORM with record expiry (TTL), crash resilience, and atomic take-once reads.
Current section
Files
Jump to
Current section
Files
lib/adapters/ets/ets.ex
defmodule ActiveMemory.Adapters.Ets do
@moduledoc false
alias ActiveMemory.Adapter
alias ActiveMemory.Adapters.Ets.Helpers
alias ActiveMemory.Query.{MatchGuards, MatchSpec}
@behaviour Adapter
def all(table) do
:ets.tab2list(table)
|> Task.async_stream(fn record -> to_struct(record, table) end)
|> Enum.into([], fn {:ok, struct} -> struct end)
end
def create_table(table, _options) do
options = table.__attributes__(:table_options)
try do
:ets.new(table, [:named_table | options])
:ok
rescue
ArgumentError -> {:error, :create_table_failed}
end
end
def delete(struct, table) do
with ets_tuple when is_tuple(ets_tuple) <- to_tuple(struct),
true <- :ets.delete_object(table, ets_tuple) do
:ok
else
_ -> {:error, :delete_failure}
end
end
def delete_all(table) do
:ets.delete_all_objects(table)
end
def one(query_map, table) when is_map(query_map) do
with {:ok, query} <- MatchGuards.build(table, query_map),
[record | []] when is_tuple(record) <- match_query(query, table) do
{:ok, to_struct(record, table)}
else
[] -> {:ok, nil}
records when is_list(records) -> {:error, :more_than_one_result}
{:error, message} -> {:error, message}
end
end
def one(query, table) when is_tuple(query) do
with [record | []] when is_tuple(record) <- select_query(query, table) do
{:ok, to_struct(record, table)}
else
[] -> {:ok, nil}
records when is_list(records) -> {:error, :more_than_one_result}
{:error, message} -> {:error, message}
end
end
def select(query_map, table) when is_map(query_map) do
with {:ok, query} <- MatchGuards.build(table, query_map),
records when is_list(records) <- match_query(query, table) do
{:ok, to_struct(records, table)}
else
[] -> {:ok, []}
{:error, message} -> {:error, message}
end
end
def select(query, table) when is_tuple(query) do
with records when is_list(records) <- select_query(query, table) do
{:ok, to_struct(records, table)}
else
[] -> {:ok, []}
{:error, message} -> {:error, message}
end
end
def write(struct, table) do
with ets_tuple when is_tuple(ets_tuple) <-
to_tuple(struct),
true <- :ets.insert(table, ets_tuple) do
{:ok, struct}
else
false -> {:error, :write_fail}
{:error, message} -> {:error, message}
end
end
defp match_query(query, table) do
:ets.match_object(table, query)
end
defp select_query(query, table) do
query_map = :erlang.apply(table, :__attributes__, [:query_map])
match_head = :erlang.apply(table, :__attributes__, [:match_head])
match_query = MatchSpec.build(query, query_map, match_head)
:ets.select(table, match_query)
end
defp to_struct(records, table) when is_list(records) do
Enum.into(records, [], fn record -> to_struct(record, table) end)
end
defp to_struct(record, table) when is_tuple(record), do: Helpers.to_struct(record, table)
defp to_tuple(record), do: Helpers.to_tuple(record)
end