Current section

Files

Jump to
subaru lib subaru.ex
Raw

lib/subaru.ex

defmodule Subaru do
@moduledoc """
The main facade and entry point for the Subaru graph database.
"""
alias Subaru.Query
@doc """
Returns the configured store module.
"""
def store do
Application.get_env(:subaru, :store, Subaru.Store.Mnesia)
end
@doc """
Runs a query plan and returns the results as a list.
"""
def run(%Query{} = query) do
Subaru.Executor.run(query, store())
end
@doc """
Generate a sortable identifier.
"""
defdelegate gen_id, to: Subaru.Id, as: :generate
@doc """
Adds an `:insert` operation for a vertex struct to a batch.
"""
def insert(batch, %{id: id} = struct) when is_list(batch) and is_binary(id) do
[{:insert, struct} | batch]
end
@doc """
Adds a `:link` operation to a batch.
"""
def link(batch, type, from_id, to_id, props \\ %{}) when is_list(batch) do
[{:link, type, from_id, to_id, props} | batch]
end
@doc """
Commits a batch of write operations to the store.
"""
def commit(batch) when is_list(batch) do
low_level_ops =
batch
|> Enum.reverse()
|> Enum.map(&to_low_level_op/1)
store().write_batch(low_level_ops)
end
# --- Passthrough functions to store ---
@doc """
Delegates to `c:Subaru.Store.Behaviour.backup/1`.
"""
def backup(path), do: store().backup(path)
@doc """
Delegates to `c:Subaru.Store.Behaviour.restore/1`.
"""
def restore(path), do: store().restore(path)
# --- Private Helpers ---
defp to_low_level_op({:insert, struct}) do
{label, properties} = struct_to_vertex_parts(struct)
value = %{label: label, properties: properties}
{:put, {:node, struct.id}, value}
end
defp to_low_level_op({:link, type, from_id, to_id, props}) do
id = gen_id()
value = %{from: from_id, to: to_id, label: type, properties: props}
{:put, {:edge, id}, value}
end
defp struct_to_vertex_parts(%{__struct__: schema} = struct) do
label =
schema
|> Module.split()
|> List.last()
|> Macro.underscore()
|> String.to_atom()
properties =
struct
|> Map.from_struct()
|> Map.drop([:id, :__struct__])
{label, properties}
end
end