# `SparrowDB.Graph`

High-level graph operations for RyuGraph.

This module provides Elixir-friendly functions for common graph operations,
abstracting away the Cypher query language for simple use cases.

# `create_node`

```elixir
@spec create_node(dynamic(), String.t(), keyword() | map()) ::
  {:ok, map()} | {:error, String.t()}
```

Creates a node with the given label and properties.

## Parameters

  * `base` - A connection reference
  * `label` - The node label
  * `properties` - A map or keyword list of properties

## Examples

    iex> SparrowDB.Graph.create_node(base, "Person", name: "Alice", age: 25)
    {:ok, %{node: true, id: ..., label: "Person", properties: %{name: "Alice", age: 25}}}

# `create_node!`

```elixir
@spec create_node!(dynamic(), String.t(), keyword() | map()) :: map()
```

Creates a node, raising on error.

Same as `create_node/3` but raises an exception on error.

# `create_relationship`

```elixir
@spec create_relationship(
  dynamic(),
  String.t() | integer(),
  String.t() | integer(),
  String.t(),
  keyword() | map()
) :: {:ok, map()} | {:error, String.t()}
```

Creates a relationship between two nodes.

## Parameters

  * `base` - A connection reference
  * `from_node_id` - The ID of the source node
  * `to_node_id` - The ID of the destination node
  * `rel_label` - The relationship label
  * `properties` - Optional properties for the relationship

## Examples

    iex> SparrowDB.Graph.create_relationship(base, node1_id, node2_id, "KNOWS",
    ...>   since: 2020
    ...> )
    {:ok, %{rel: true, id: ..., label: "KNOWS", src: ..., dst: ..., properties: %{since: 2020}}}

# `create_relationship!`

```elixir
@spec create_relationship!(
  dynamic(),
  String.t() | integer(),
  String.t() | integer(),
  String.t(),
  keyword() | map()
) :: map()
```

Creates a relationship between two nodes, raising on error.

Same as `create_relationship/5` but raises an exception on error.

# `delete_node`

```elixir
@spec delete_node(dynamic(), String.t() | integer(), keyword()) ::
  {:ok, :deleted} | {:error, String.t()}
```

Deletes a node and optionally its relationships.

## Parameters

  * `base` - A connection reference
  * `node_id` - The ID of the node to delete
  * `opts` - Deletion options

## Options

  * `:detach` - If true, deletes the node and all its relationships (default: false)

## Examples

    iex> SparrowDB.Graph.delete_node(base, node_id)
    {:ok, :deleted}

    iex> SparrowDB.Graph.delete_node(base, node_id, detach: true)
    {:ok, :deleted}

# `find_nodes`

```elixir
@spec find_nodes(dynamic(), String.t(), map() | String.t() | nil, keyword()) ::
  {:ok, [map()]} | {:error, String.t()}
```

Finds nodes matching the given criteria.

## Parameters

  * `base` - A connection reference
  * `label` - The node label to search for
  * `where_clause` - Optional WHERE clause conditions as a map or string
  * `opts` - Query options

## Options

  * `:limit` - Maximum number of results to return
  * `:order_by` - Property to order results by
  * `:desc` - If true, order results in descending order (default: false)

## Examples

    iex> SparrowDB.Graph.find_nodes(base, "Person")
    {:ok, [%{node: true, label: "Person", properties: %{...}}, ...]}

    iex> SparrowDB.Graph.find_nodes(base, "Person", %{age: 25})
    {:ok, [%{node: true, label: "Person", properties: %{name: "Alice", age: 25}}]}

    iex> SparrowDB.Graph.find_nodes(base, "Person", "n.age > 20", limit: 10)
    {:ok, [...]}

# `find_nodes!`

```elixir
@spec find_nodes!(dynamic(), String.t(), map() | String.t() | nil, keyword()) :: [
  map()
]
```

Finds nodes matching the given criteria, raising on error.

Same as `find_nodes/4` but raises an exception on error.

# `get_neighbors`

```elixir
@spec get_neighbors(dynamic(), String.t() | integer(), keyword()) ::
  {:ok, [map()]} | {:error, String.t()}
```

Gets all neighbors of a node.

## Parameters

  * `base` - A connection reference
  * `node_id` - The ID of the node
  * `opts` - Options for the query

## Options

  * `:direction` - `:out` (default), `:in`, or `:both`
  * `:rel_label` - Only follow relationships with this label
  * `:depth` - How many hops to traverse (default: 1)

## Examples

    iex> SparrowDB.Graph.get_neighbors(base, node_id)
    {:ok, [%{node: true, ...}, ...]}

    iex> SparrowDB.Graph.get_neighbors(base, node_id,
    ...>   direction: :both,
    ...>   rel_label: "KNOWS"
    ...> )
    {:ok, [...]}

# `get_neighbors!`

```elixir
@spec get_neighbors!(dynamic(), String.t() | integer(), keyword()) :: [map()]
```

Gets all neighbors of a node, raising on error.

Same as `get_neighbors/3` but raises an exception on error.

# `shortest_path`

```elixir
@spec shortest_path(
  dynamic(),
  String.t() | integer(),
  String.t() | integer(),
  keyword()
) ::
  {:ok, map()} | {:error, String.t()}
```

Finds the shortest path between two nodes.

## Parameters

  * `base` - A connection reference
  * `from_node_id` - The ID of the start node
  * `to_node_id` - The ID of the end node
  * `opts` - Path finding options

## Options

  * `:rel_label` - Only follow relationships with this label
  * `:max_length` - Maximum path length (default: no limit)

## Examples

    iex> SparrowDB.Graph.shortest_path(base, node1_id, node2_id)
    {:ok, %{nodes: [...], rels: [...]}}

    iex> SparrowDB.Graph.shortest_path(base, node1_id, node2_id,
    ...>   rel_label: "KNOWS",
    ...>   max_length: 3
    ...> )
    {:ok, %{nodes: [...], rels: [...]}}

# `update_node`

```elixir
@spec update_node(dynamic(), String.t() | integer(), keyword() | map()) ::
  {:ok, map()} | {:error, String.t()}
```

Updates properties of a node.

## Parameters

  * `base` - A connection reference
  * `node_id` - The ID of the node to update
  * `properties` - Properties to set or update

## Examples

    iex> SparrowDB.Graph.update_node(base, node_id, age: 26, city: "New York")
    {:ok, %{node: true, properties: %{age: 26, city: "New York", ...}}}

# `update_node!`

```elixir
@spec update_node!(dynamic(), String.t() | integer(), keyword() | map()) :: map()
```

Updates properties of a node, raising on error.

Same as `update_node/3` but raises an exception on error.

---

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