# `AshNeo4j.Neo4jHelper`
[🔗](https://github.com/diffo-dev/ash_neo4j/blob/v0.10.1/lib/neo4j_helper.ex#L5)

AshNeo4j DataLayer Neo4j Helper

# `bulk_detach_delete`

Bulk destroy (#361): deletes every node of `label` matching `conditions` that
isn't protected by a preservation `guard`. Returns `{:ok, %Bolty.Response{}}` —
with captured pre-delete node data when `return?`.

# `create_node`

Creates a neo4j node with labels and properties

## Examples
```
iex> {result, _} = AshNeo4j.Neo4jHelper.create_node([:Cinema, :Actor], %{name: "Bill Nighy"})
iex> result
:ok
```

# `delete_all`

```elixir
@spec delete_all() ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Delete all neo4j nodes and relationships

## Examples
```
iex> {result, _} = AshNeo4j.Neo4jHelper.delete_all()
iex> result
:ok
```

# `delete_node_filtered`

Single filtered + guarded destroy (#361): deletes the `id`-matched node when it
satisfies `filter_conditions` (optimistic lock) and isn't `guard`-protected.
`{:ok, _}` when deleted, `{:error, :nothing_deleted}` otherwise.

# `delete_nodes`

Delete neo4j nodes

## Examples
```
iex> {result, _} = AshNeo4j.Neo4jHelper.delete_nodes(:Actor)
iex> result
:ok
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy"})
iex> {result, _} = AshNeo4j.Neo4jHelper.delete_nodes(:Actor, %{name: "Bill Nighy"})
iex> result
:ok
```

# `merge_node`

```elixir
@spec merge_node(atom(), map()) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Merges a neo4j node with label and properties

## Examples
```
iex> {result, _} = AshNeo4j.Neo4jHelper.merge_node(:Actor, %{name: "Bill Nighy", born: 1949})
iex> result
:ok
```

# `node_matching`

The optimistic-lock existence check (#361): does the `id`-matched node satisfy
`filter_conditions`? Returns `{:ok, %Bolty.Response{}}`.

# `nodes_relate_how?`

```elixir
@spec nodes_relate_how?(atom(), map(), atom(), map(), [tuple()]) ::
  :error | false | true
```

Tests if two nodes are related by traversal
  ## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Keira Knightley"})
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Keira Knightley"}, :Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing)
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Bill Nighy"}, :Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing)
iex> AshNeo4j.Neo4jHelper.nodes_relate_how?(:Actor, %{name: "Bill Nighy"}, :Actor, %{name: "Keira Knightley"}, [ACTED_IN: :outgoing, ACTED_IN: :incoming])
true
```

# `nodes_relate_how?`

```elixir
@spec nodes_relate_how?(atom(), map(), atom(), map(), atom(), atom()) ::
  :error | false | true
```

Tests if two nodes are directly related
  ## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy", born: 1949})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Bill Nighy"}, :Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing)
iex> AshNeo4j.Neo4jHelper.nodes_relate_how?(:Actor, %{name: "Bill Nighy"}, :Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing)
true
```

# `read_limited`

Reads limited nodes from Neo4j, given label, limit and optionally properties

## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy", born: 1949})
iex> {:ok, %{records: records}} = AshNeo4j.Neo4jHelper.read_limited(:Actor, 1)
iex> length(records)
1
```

# `read_nodes`

Reads nodes from Neo4j, given label, and optionally properties

## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy", born: 1949})
iex> {:ok, %{records: records}} = AshNeo4j.Neo4jHelper.read_nodes(:Actor, %{name: "Bill Nighy"})
iex> length(records)
1
```

# `read_nodes_related`

Reads nodes from Neo4j, returning any related nodes

## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy", born: 1949})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> :ok = AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Bill Nighy"}, [{:Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing, false}])
iex> {:ok, %{records: records}} = AshNeo4j.Neo4jHelper.read_nodes_related(:Actor, %{name: "Bill Nighy"})
iex> length(records)
1
```

# `relate_nodes`

```elixir
@spec relate_nodes(atom() | [atom()], map(), list()) :: {:error, Exception.t()} | :ok
```

Creates source neo4j node with label, properties and relationships to existing nodes

## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{title: "Bill Nighy"})
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{title: "Keira Knightley"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Bend it Like Beckham"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "The Immitation Game"})

iex> :ok = AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Bill Nighy"}, [{:Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing, false}])
iex> :ok = AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Keira Knightley"}, [{:Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing, false}, {:Movie, %{title: "Bend it Like Beckham"}, :ACTED_IN, :outgoing, false}])
```

# `relate_nodes`

```elixir
@spec relate_nodes(atom() | [atom()], map(), atom() | [atom()], map(), atom(), atom()) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Relates two nodes with a relationship type, merging relationship
  ## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy", born: 1949})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> {result, _} = AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Bill Nighy"}, :Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing)
iex> result
:ok
```

# `relate_nodes`

```elixir
@spec relate_nodes(
  atom() | [atom()],
  map(),
  atom() | [atom()],
  map(),
  atom(),
  atom(),
  keyword()
) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Relates two nodes, honouring exclusivity and an optional `changeset.filter` guard.

`opts`:
  * `:exclusive` — `{source_exclusive?, destination_exclusive?}` (default `{false, false}`),
    selecting the plain / unrelate-source / unrelate-destination / unrelate-both render.
  * `:guard` — a `changeset.filter` condition list (#368) gating the attach on the
    live source node; a guard miss yields zero rows ⇒ the caller raises `StaleRecord`.

# `relate_nodes_unrelating_destination`

```elixir
@spec relate_nodes_unrelating_destination(
  atom(),
  map(),
  atom(),
  map(),
  atom(),
  atom(),
  list()
) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Relates two nodes unrelating the destination node from any similar relationships
 ## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Fan], %{name: "Matt"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Bend it Like Beckham"})
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Fan, %{name: "Matt"}, :Movie, %{title: "Love Actually"}, :FAVOURITE, :outgoing)
iex> {result, _} = AshNeo4j.Neo4jHelper.relate_nodes_unrelating_destination(:Movie, %{title: "Bend it Like Beckham"}, :Fan, %{name: "Matt"}, :FAVOURITE, :incoming)
iex> result
:ok
```

# `relate_nodes_unrelating_source`

```elixir
@spec relate_nodes_unrelating_source(
  atom(),
  map(),
  atom(),
  map(),
  atom(),
  atom(),
  list()
) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Relates two nodes unrelating the source node from any similar relationships
 ## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Fan], %{name: "Matt"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Bend it Like Beckham"})
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Fan, %{name: "Matt"}, :Movie, %{title: "Love Actually"}, :FAVOURITE, :outgoing)
iex> {result, _} = AshNeo4j.Neo4jHelper.relate_nodes_unrelating_source(:Fan, %{name: "Matt"}, :Movie, %{title: "Bend it Like Beckham"}, :FAVOURITE, :outgoing)
iex> result
:ok
```

# `relate_nodes_unrelating_source_and_destination`

```elixir
@spec relate_nodes_unrelating_source_and_destination(
  atom(),
  map(),
  atom(),
  map(),
  atom(),
  atom(),
  list()
) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Relates two nodes unrelating the source and destination node from any similar relationships
 ## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Person], %{name: "Marlo"})
iex> AshNeo4j.Neo4jHelper.create_node([:Person], %{name: "Harry"})
iex> AshNeo4j.Neo4jHelper.create_node([:Person], %{name: "Marion"})
iex> AshNeo4j.Neo4jHelper.create_node([:Person], %{name: "Robin"})
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Person, %{name: "Marlo"}, :Person, %{name: "Harry"}, :PARTNER, :outgoing)
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Person, %{name: "Marion"}, :Person, %{name: "Robin"}, :PARTNER, :outgoing)
iex> {result, _} = AshNeo4j.Neo4jHelper.relate_nodes_unrelating_source_and_destination(:Person, %{name: "Marlo"}, :Person, %{name: "Robin"}, :PARTNER, :outgoing)
iex> result
:ok
```

# `safe_delete_nodes`

Safely delete neo4j nodes, delete is guarded by relationships

## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Keira Knightley"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Bend it Like Beckham"})
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Keira Knightley"}, [{:Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing, false},
...> {:Movie, %{title: "Bend it Like Beckham"}, :ACTED_IN, :outgoing, false}])
iex> {result, _} = AshNeo4j.Neo4jHelper.safe_delete_nodes(:Actor, %{name: "Keira Knightley"}, [{:ACTED_IN, :outgoing, :Movie}, {:LIVES_AT, :outgoing, :Place}])
iex> result
:error
iex> {result, _} = AshNeo4j.Neo4jHelper.safe_delete_nodes(:Actor, %{name: "Keira Knightley"}, [{:LIVES_AT, :outgoing, :Place}])
iex> result
:ok
```

# `unrelate_nodes`

```elixir
@spec unrelate_nodes(
  atom() | [atom()],
  map(),
  atom() | [atom()],
  map(),
  atom(),
  atom(),
  list()
) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Unrelates two nodes with a relationship type
  ## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy", born: 1949})
iex> AshNeo4j.Neo4jHelper.create_node([:Movie], %{title: "Love Actually"})
iex> AshNeo4j.Neo4jHelper.relate_nodes(:Actor, %{name: "Bill Nighy"}, :Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing)
iex> {result, _} = AshNeo4j.Neo4jHelper.unrelate_nodes(:Actor, %{name: "Bill Nighy"}, :Movie, %{title: "Love Actually"}, :ACTED_IN, :outgoing)
iex> result
:ok
```

# `update_node`

Updates neo4j node properties

## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:Actor], %{name: "Bill Nighy"})
iex> {result, _} = AshNeo4j.Neo4jHelper.update_node(:Actor, %{name: "Bill Nighy"}, %{born: 1949})
iex> result
:ok
```

# `update_node_labels`

```elixir
@spec update_node_labels(atom() | [atom()], map(), [atom()], [atom()]) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Adds and/or removes labels on an existing node (matched by label + properties).

A node's label set drives `AshNeo4j.worlds/1`, so this places a node in — or
strips it of — a resolvable world. Useful in tests: create a node via Ash,
then mutate its labels to set up a chosen world (or an unresolvable one).

## Examples
```
iex> AshNeo4j.Neo4jHelper.create_node([:SRM, :Place], %{name: "Sydney"})
iex> {result, _} = AshNeo4j.Neo4jHelper.update_node_labels(:Place, %{name: "Sydney"}, [], [:SRM])
iex> result
:ok
```

# `upsert_node`

```elixir
@spec upsert_node(atom() | [atom()], map(), map(), map(), [atom()]) ::
  {:error,
   %{:__exception__ =&gt; true, :__struct__ =&gt; atom(), optional(atom()) =&gt; any()}}
  | {:ok, any()}
```

Atomic upsert (#379): MERGE on `merge_props` (the identity), `ON CREATE SET` the
rest (`create_props`), `ON MATCH SET` the `set_on_upsert` fields (`match_props`).

`create_labels` (#392) are extra labels added with `ON CREATE SET n:Label` so an
upserted node carries the same full label set a plain create writes.

---

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