Current section

Files

Jump to
subaru lib subaru repo.ex
Raw

lib/subaru/repo.ex

defmodule Subaru.Repo do
@moduledoc """
GenServer that manages a Subaru graph repository.
Each repository is a supervised process that:
- Initializes the storage adapter on startup
- Provides runtime functions for CRUD operations
- Handles transactions
## Usage
Define a repo module in your application:
defmodule MyApp.Graph do
use Subaru,
otp_app: :my_app,
adapter: Subaru.Adapters.Mnesia
end
Add it to your supervision tree:
children = [
MyApp.Graph
]
Then use it:
MyApp.Graph.put(%{id: "alice", name: "Alice"})
MyApp.Graph.get("alice")
"""
use GenServer
defstruct [:repo, :adapter, :config]
@type t :: %__MODULE__{
repo: module(),
adapter: module(),
config: keyword()
}
# Client API
@doc false
def start_link({repo, otp_app, adapter, opts}) do
config = Application.get_env(otp_app, repo, [])
merged_opts = Keyword.merge(config, opts)
GenServer.start_link(__MODULE__, {repo, adapter, merged_opts}, name: repo)
end
@doc false
def child_spec({repo, otp_app, adapter, opts}) do
%{
id: repo,
start: {__MODULE__, :start_link, [{repo, otp_app, adapter, opts}]},
type: :worker,
restart: :permanent,
shutdown: 5000
}
end
# GenServer callbacks
@impl true
def init({repo, adapter, opts}) do
case adapter.init(repo, opts) do
:ok ->
state = %__MODULE__{
repo: repo,
adapter: adapter,
config: opts
}
{:ok, state}
{:error, reason} ->
{:stop, reason}
end
end
@impl true
def terminate(_reason, %__MODULE__{adapter: adapter, repo: repo}) do
adapter.stop(repo)
:ok
end
@impl true
def handle_call(:get_adapter, _from, state) do
{:reply, state.adapter, state}
end
@impl true
def handle_call(:get_config, _from, state) do
{:reply, state.config, state}
end
end