# `Mnemosyne.GraphBackend`
[🔗](https://github.com/edlontech/mnemosyne/blob/main/lib/mnemosyne/graph_backend.ex#L1)

Behaviour for unified graph persistence and querying backends.

Implementations handle storing, retrieving, and querying knowledge graph
nodes through a single interface, replacing the separate Storage and
in-memory Graph modules with a database-agnostic contract.

## Callbacks

- `init/1` - Initialize the backend with configuration options.
- `apply_changeset/2` - Persist a batch of node additions and links.
- `delete_nodes/2` - Remove nodes by their IDs.
- `find_candidates/6` - Query for nodes matching type/embedding/tag criteria.
- `get_node/2` - Fetch a single node by ID.
- `get_linked_nodes/3` - Fetch linked nodes, optionally filtered by edge type.

Read callbacks (`find_candidates`, `get_node`, `get_linked_nodes`) return state
for interface uniformity but must not rely on state mutation — callers may
discard the returned state in read-only contexts.

# `scored_node`

```elixir
@type scored_node() :: {struct(), float()}
```

# `state`

```elixir
@type state() :: term()
```

# `apply_changeset`

```elixir
@callback apply_changeset(Mnemosyne.Graph.Changeset.t(), state()) ::
  {:ok, state()} | {:error, Mnemosyne.Errors.error()}
```

# `delete_metadata`

```elixir
@callback delete_metadata([String.t()], state()) :: {:ok, state()}
```

# `delete_nodes`

```elixir
@callback delete_nodes([String.t()], state()) ::
  {:ok, state()} | {:error, Mnemosyne.Errors.error()}
```

# `find_candidates`

```elixir
@callback find_candidates(
  node_types :: [atom()],
  query_embedding :: [float()],
  tag_embeddings :: [[float()]],
  value_fn_config :: %{module: module(), params: %{required(atom()) =&gt; map()}},
  opts :: keyword(),
  state()
) :: {:ok, [scored_node()], state()} | {:error, Mnemosyne.Errors.error()}
```

# `get_linked_nodes`

```elixir
@callback get_linked_nodes([String.t()], Mnemosyne.Graph.Edge.edge_type() | nil, state()) ::
  {:ok, [struct()], state()}
```

# `get_metadata`

```elixir
@callback get_metadata([String.t()], state()) ::
  {:ok, %{required(String.t()) =&gt; struct()}, state()}
```

# `get_node`

```elixir
@callback get_node(String.t(), state()) :: {:ok, struct() | nil, state()}
```

# `get_nodes_by_type`

```elixir
@callback get_nodes_by_type(node_types :: [atom()], state()) ::
  {:ok, [struct()], state()} | {:error, Mnemosyne.Errors.error()}
```

# `init`

```elixir
@callback init(opts :: keyword()) :: {:ok, state()} | {:error, Mnemosyne.Errors.error()}
```

# `update_metadata`

```elixir
@callback update_metadata(%{required(String.t()) =&gt; struct()}, state()) :: {:ok, state()}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
