defmodule EctoQLC.Adapters.Mnesia do @moduledoc """ Adapter module for [Mnesia](https://www.erlang.org/doc/man/mnesia.html). ## Clustering There is currently no support for automatic clustering or unsplit. If you decide to deploy EctoQLC.Adapters.Mnesia in a cluster you might find the following resources useful: * https://www.erlang.org/doc/apps/mnesia/mnesia_chap5#distribution-and-fault-tolerance * https://github.com/danschultzer/pow/blob/master/lib/pow/store/backend/mnesia_cache.ex * https://github.com/danschultzer/pow/blob/master/lib/pow/store/backend/mnesia_cache/unsplit.ex * https://github.com/uwiger/unsplit """ use EctoQLC.Adapters.QLC, driver: :mnesia @impl Ecto.Adapter.Storage def storage_down(_opts) do with :stopped <- :mnesia.stop(), :ok <- :mnesia.delete_schema([node()]) do :ok else {:error, reason} -> raise RuntimeError, :mnesia.error_description(reason) end end @impl Ecto.Adapter.Storage def storage_status(_opts) do case :mnesia.system_info(:is_running) do :no -> :down :yes -> :up value -> {:error, value} end end @impl Ecto.Adapter.Storage def storage_up(_opts) do with :stopped <- :mnesia.stop, :ok <- :mnesia.create_schema([node()]) do :ok else {:aborted, {:already_exists, _table, _node, _storage_type}} -> {:error, :already_up} {:error, {_, {:already_exists, _}}} -> {:error, :already_up} {:error, reason} -> raise RuntimeError, :mnesia.error_description(reason) end end @impl Ecto.Adapter.Transaction def transaction(_adapter_meta, _opts, fun) do # mnesia transaction support functions with args # with would allow it to forward options if needed. case :mnesia.transaction(fun) do {:aborted, reason} -> {:error, reason} {:atomic, result} -> {:ok, result} result -> {:ok, result} end end @impl Ecto.Adapter.Transaction def in_transaction?(_adapter_meta), do: :mnesia.is_transaction() @impl Ecto.Adapter.Transaction def rollback(adapter_meta, %_schema{} = value) do if in_transaction?(adapter_meta) do throw(:mnesia.abort(value)) else raise "cannot call rollback outside of transaction" end end end