# `RDF.Graph`
[🔗](https://github.com/rdf-elixir/rdf-ex/blob/v3.0.1/lib/rdf/model/graph.ex#L1)

A set of RDF triples with an optional name.

`RDF.Graph` implements:

- the `RDF.Data.Source` protocol
- Elixir's `Enumerable` protocol
- Elixir's `Collectable` protocol
- Elixir's `Inspect` protocol
- Elixir's `Access` behaviour

# `follow_fun`

```elixir
@type follow_fun() :: (RDF.Resource.t(), RDF.IRI.t(), non_neg_integer() -&gt; boolean())
```

# `get_and_update_description_fun`

```elixir
@type get_and_update_description_fun() :: (RDF.Description.t() -&gt;
                                       {RDF.Description.t(), input()} | :pop)
```

# `graph_description`

```elixir
@type graph_description() :: %{
  required(RDF.Star.Statement.subject()) =&gt; RDF.Description.t()
}
```

# `input`

```elixir
@type input() ::
  t()
  | RDF.Star.Statement.coercible()
  | {RDF.Star.Statement.coercible_subject(), RDF.Description.input()}
  | RDF.Description.t()
  | RDF.Dataset.t()
  | %{
      required(RDF.Star.Statement.coercible_subject()) =&gt; %{
        required(RDF.Star.Statement.coercible_predicate()) =&gt;
          RDF.Star.Statement.coercible_object()
          | [RDF.Star.Statement.coercible_object()]
      }
    }
  | [input()]
```

# `t`

```elixir
@type t() :: %RDF.Graph{
  base_iri: RDF.IRI.t() | nil,
  descriptions: graph_description(),
  name: RDF.Star.Statement.graph_name(),
  prefixes: RDF.PrefixMap.t()
}
```

# `update_description_fun`

```elixir
@type update_description_fun() :: (RDF.Description.t() -&gt; RDF.Description.t())
```

# `add`

```elixir
@spec add(t(), input(), keyword()) :: t()
```

Add triples to a `RDF.Graph`.

The `input` can be provided

- as a single statement tuple
- a nested subject-predicate-object map
- a `RDF.Description`
- a `RDF.Graph`
- a `RDF.Dataset`
- or a list with any combination of the former

When the statements to be added are given as another `RDF.Graph`,
the graph name must not match graph name of the graph to which the statements
are added. As opposed to that, `RDF.Data.merge/2` will produce a `RDF.Dataset`
containing both graphs.

Also, when the statements to be added are given as another `RDF.Graph`, the
prefixes of this graph will be added. In case of conflicting prefix mappings
the original prefix from `graph` will be kept.

When the statements to be added are given as a `RDF.Dataset` the data from
all of its graphs are added.

RDF-star annotations to be added to all the given statements can be specified with
the `:add_annotations`, `:put_annotations` or `:put_annotation_properties` keyword
options. They have different addition semantics similar to the `add_annotations/3`,
`put_annotations/3` and `put_annotation_properties/3` counterparts.

# `add_annotations`

```elixir
@spec add_annotations(t(), input(), RDF.Description.input() | nil) :: t()
```

Adds RDF-star annotations to the given set of statements.

The set of `statements` can be given in any input form (see `add/3`).

The predicate-objects pairs to be added as annotations can be given as a tuple,
a list of tuples or a map.

# `add_prefixes`

```elixir
@spec add_prefixes(
  t(),
  RDF.PrefixMap.t() | map() | keyword() | nil,
  RDF.PrefixMap.conflict_resolver() | nil
) :: t()
```

Adds `prefixes` to the given `graph`.

The `prefixes` mappings can be given as any structure convertible to a
`RDF.PrefixMap`.

When a prefix with another mapping already exists it will be overwritten with
the new one. This behaviour can be customized by providing a `conflict_resolver`
function. See `RDF.PrefixMap.merge/3` for more on that.

# `annotations`

```elixir
@spec annotations(t()) :: t()
```

Returns the `RDF.Graph` of all annotations.

Note: The graph includes only triples where the subject is a quoted triple.
Triples where only the object is a quoted triple are NOT included.

# `base_iri`

```elixir
@spec base_iri(t()) :: RDF.IRI.t() | nil
```

Returns the base IRI of the given `graph`.

# `build`
*macro* 

Builds an `RDF.Graph` from a description of its content in a graph DSL.

All available opts of `new/2` are also supported here.

For a description of the DSL see [this guide](https://rdf-elixir.dev/rdf-ex/description-and-graph-dsl.html).

# `canonical_hash`

# `canonicalize`

```elixir
@spec canonicalize(
  t(),
  keyword()
) :: t()
```

Canonicalizes the blank nodes of a graph according to the RDF Dataset Canonicalization spec.

See the `RDF.Canonicalization` module documentation on available options.

## Example

    iex> RDF.Graph.new([{~B<foo>, EX.p(), ~B<bar>}, {~B<bar>, EX.p(), ~B<foo>}])
    ...> |> RDF.Graph.canonicalize()
    RDF.Graph.new([{~B<c14n0>, EX.p(), ~B<c14n1>}, {~B<c14n1>, EX.p(), ~B<c14n0>}])

# `change_name`

```elixir
@spec change_name(t(), RDF.Star.Statement.coercible_graph_name()) :: t()
```

Changes the graph name of `graph`.

# `clear`

```elixir
@spec clear(t()) :: t()
```

Removes all triples from `graph`.

This function is useful for getting an empty graph based on the settings of
another graph, as this function keeps graph name, base IRI and default prefixes
as they are and just removes the triples.

# `clear_base_iri`

```elixir
@spec clear_base_iri(t()) :: t()
```

Clears the base IRI of the given `graph`.

# `clear_metadata`

```elixir
@spec clear_metadata(t()) :: t()
```

Clears the base IRI and all prefixes of the given `graph`.

# `clear_name`

```elixir
@spec clear_name(t()) :: t()
```

Clears the name of the given `graph` to `nil`.

# `clear_prefixes`

```elixir
@spec clear_prefixes(t()) :: t()
```

Clears all prefixes of the given `graph`.

# `delete`

```elixir
@spec delete(t(), input(), keyword()) :: t()
```

Deletes statements from a `RDF.Graph`.

When the statements to be deleted are given as another `RDF.Graph`,
the graph name must not match graph name of the graph from which the statements
are deleted. If you want to delete only statements with matching graph names, you can
use `RDF.Data.delete/2`.

## Options

- `:delete_annotations` - Which RDF-star annotations of the deleted statements
  should be deleted. Any of the possible values of `delete_annotations/3` can
  be provided here. By default, no annotations of the deleted statements will
  be removed.
- `:add_annotations`, `:put_annotations`, `:put_annotation_properties` -
  Add annotations about the deleted statements with the respective addition
  semantics similar to `add_annotations/3`, `put_annotations/3` and
  `put_annotation_properties/3`.
- `:on_graph_mismatch` - Controls behavior when deleting quads whose graph name
  doesn't match this graph's name:
  - `:warn` (default) - Log a warning and proceed with deletion
  - `:ignore` - Silently ignore the graph name mismatch and proceed
  - `:skip` - Skip the statement (don't delete)
  - `:error` - Raise an `ArgumentError`

  Note: The graph names must match exactly. A quad with `nil` as graph name
  to a named graph (or vice versa) is considered a mismatch.

# `delete_annotations`

```elixir
@spec delete_annotations(
  t(),
  input(),
  boolean()
  | RDF.Star.Statement.coercible_predicate()
  | [RDF.Star.Statement.coercible_predicate()]
) :: t()
```

Deletes RDF-star annotations of a given set of statements.

The `statements` can be given in any input form (see `add/3`).

If `true` is given as the third argument or is `delete_annotations/2` is used,
all annotations of the given `statements` are deleted.

If a single predicate or list of predicates is given only statements with
these predicates from the annotations of the given `statements` are deleted.

# `delete_descriptions`

```elixir
@spec delete_descriptions(
  t(),
  RDF.Star.Statement.coercible_subject()
  | [RDF.Star.Statement.coercible_subject()],
  keyword()
) :: t()
```

Deletes all statements with the given `subjects`.

If `subjects` contains subjects that are not in `graph`, they're simply ignored.

The optional `:delete_annotations` keyword option allows to set which of
the RDF-star annotations of the deleted statements should be deleted.
Any of the possible values of `delete_annotations/3` can be provided here.
By default, no annotations of the deleted statements will be removed.
Alternatively, the `:add_annotations`, `:put_annotations` or `:put_annotation_properties`
keyword options can be used to add annotations about the deleted statements
with the addition semantics similar to the respective `add_annotations/3`,
`put_annotations/3` and `put_annotation_properties/3` counterparts.

# `delete_predications`

```elixir
@spec delete_predications(
  t(),
  {RDF.Star.Statement.coercible_subject(),
   RDF.Star.Statement.coercible_predicate()}
  | RDF.Star.Triple.coercible()
  | [
      {RDF.Star.Statement.coercible_subject(),
       RDF.Star.Statement.coercible_predicate()}
      | RDF.Star.Triple.coercible()
    ],
  keyword()
) :: t()
```

Deletes all statements with the given subject-predicate pairs.

If `predications` contains subject-predicate pairs that are not in `graph`, they're simply ignored.

The optional `:delete_annotations` keyword option allows to set which of
the RDF-star annotations of the deleted statements should be deleted.
Any of the possible values of `delete_annotations/3` can be provided here.
By default, no annotations of the deleted statements will be removed.
Alternatively, the `:add_annotations`, `:put_annotations` or `:put_annotation_properties`
keyword options can be used to add annotations about the deleted statements
with the addition semantics similar to the respective `add_annotations/3`,
`put_annotations/3` and `put_annotation_properties/3` counterparts.

# `delete_prefixes`

```elixir
@spec delete_prefixes(t(), RDF.PrefixMap.t()) :: t()
```

Deletes `prefixes` from the given `graph`.

The `prefixes` can be a single prefix or a list of prefixes.
Prefixes not in prefixes of the graph are simply ignored.

# `delete_subjects`

# `delete_subjects`

# `describes?`

```elixir
@spec describes?(t(), RDF.Star.Statement.coercible_subject()) :: boolean()
```

Checks if a `RDF.Graph` contains statements about the given resource.

## Examples

      iex> RDF.Graph.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Graph.describes?(EX.S1)
      true
      iex> RDF.Graph.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Graph.describes?(EX.S2)
      false

# `description`

```elixir
@spec description(t(), RDF.Star.Statement.coercible_subject()) :: RDF.Description.t()
```

Returns the description of the given `subject` in the given `graph`.

As opposed to `get/3` this function returns an empty `RDF.Description` when
the subject does not exist in the given `graph`.

## Examples

    iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
    ...> |> RDF.Graph.description(EX.S1)
    RDF.Description.new(EX.S1, init: {EX.P1, EX.O1})

    iex> RDF.Graph.description(RDF.Graph.new(), EX.Foo)
    RDF.Description.new(EX.Foo)

# `descriptions`

```elixir
@spec descriptions(t()) :: [RDF.Description.t()]
```

All `RDF.Description`s within a `RDF.Graph`.

# `empty?`

```elixir
@spec empty?(t()) :: boolean()
```

Returns if the given `graph` is empty.

Note: You should always prefer this over the use of `Enum.empty?/1` as it is significantly faster.

# `equal?`

```elixir
@spec equal?(t() | any(), t() | any()) :: boolean()
```

Checks if two `RDF.Graph`s are equal.

Two `RDF.Graph`s are considered to be equal if they contain the same triples
and have the same name. The prefixes of the graph are irrelevant for equality.

# `fetch`

```elixir
@spec fetch(t(), RDF.Star.Statement.coercible_subject()) ::
  {:ok, RDF.Description.t()} | :error
```

Fetches the description of the given subject.

When the subject can not be found `:error` is returned.

## Examples

    iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
    ...> |> RDF.Graph.fetch(EX.S1)
    {:ok, RDF.Description.new(EX.S1, init: {EX.P1, EX.O1})}
    iex> RDF.Graph.new() |> RDF.Graph.fetch(EX.foo)
    :error

# `get`

```elixir
@spec get(t(), RDF.Star.Statement.coercible_subject(), any()) ::
  RDF.Description.t() | any()
```

Gets the description of the given `subject` in the given `graph`.

When the subject can not be found the optionally given default value or
`nil` is returned.

## Examples

    iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
    ...> |> RDF.Graph.get(EX.S1)
    RDF.Description.new(EX.S1, init: {EX.P1, EX.O1})

    iex> RDF.Graph.get(RDF.Graph.new(), EX.Foo)
    nil

    iex> RDF.Graph.get(RDF.Graph.new(), EX.Foo, :bar)
    :bar

# `get_and_update`

```elixir
@spec get_and_update(
  t(),
  RDF.Star.Statement.coercible_subject(),
  get_and_update_description_fun()
) ::
  {RDF.Description.t(), t()}
```

Gets and updates the description of the given subject, in a single pass.

Invokes the passed function on the `RDF.Description` of the given subject;
this function should return either `{description_to_return, new_description}` or `:pop`.

If the passed function returns `{description_to_return, new_description}`, the
return value of `get_and_update` is `{description_to_return, new_graph}` where
`new_graph` is the input `Graph` updated with `new_description` for
the given subject.

If the passed function returns `:pop` the description for the given subject is
removed and a `{removed_description, new_graph}` tuple gets returned.

## Examples

    iex> RDF.Graph.new({EX.S, EX.P, EX.O})
    ...> |> RDF.Graph.get_and_update(EX.S, fn current_description ->
    ...>      {current_description, {EX.P, EX.NEW}}
    ...>    end)
    {RDF.Description.new(EX.S, init: {EX.P, EX.O}), RDF.Graph.new({EX.S, EX.P, EX.NEW})}

# `include?`

```elixir
@spec include?(t(), input(), keyword()) :: boolean()
```

Checks if the given `input` statements exist within `graph`.

# `intersection`

```elixir
@spec intersection(t(), t() | RDF.Dataset.t() | RDF.Description.t() | input()) :: t()
```

Returns a new graph that is the intersection of the given `graph` with the given `data`.

The `data` can be given in any form an `RDF.Graph` can be created from.
When a `RDF.Dataset` is given, the aggregation of all of its graphs is used
for the intersection.

## Examples

    iex> RDF.Graph.new({EX.S1, EX.p(), [EX.O1, EX.O2]})
    ...> |> RDF.Graph.intersection({EX.S1, EX.p(), [EX.O2, EX.O3]})
    RDF.Graph.new({EX.S1, EX.p(), EX.O2})

# `isomorphic?`

```elixir
@spec isomorphic?(t(), t(), keyword()) :: boolean()
```

Checks whether two graphs are equal, regardless of the concrete names of the blank nodes they contain.

See the `RDF.Canonicalization` module documentation on available options.

## Examples

    iex> RDF.Graph.new([{~B<foo>, EX.p(), ~B<bar>}, {~B<bar>, EX.p(), 42}])
    ...> |> RDF.Graph.isomorphic?(
    ...>      RDF.Graph.new([{~B<b1>, EX.p(), ~B<b2>}, {~B<b2>, EX.p(), 42}]))
    true

    iex> RDF.Graph.new([{~B<foo>, EX.p(), ~B<bar>}, {~B<bar>, EX.p(), 42}])
    ...> |> RDF.Graph.isomorphic?(
    ...>      RDF.Graph.new([{~B<b1>, EX.p(), ~B<b2>}, {~B<b3>, EX.p(), 42}]))
    false

# `map`

```elixir
@spec map(t(), RDF.Star.Statement.term_mapping()) :: map()
```

Returns a nested map of a `RDF.Graph` where each element from its triples is mapped with the given function.

The function `fun` will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate` or `:object`,
while `rdf_term` is the RDF term to be mapped. When the given function returns
`nil` this will be interpreted as an error and will become the overhaul result
of the `map/2` call.

Note: RDF-star statements where the subject or object is a triple will be ignored.

## Examples

    iex> RDF.Graph.new([
    ...>   {~I<http://example.com/S1>, ~I<http://example.com/p>, ~L"Foo"},
    ...>   {~I<http://example.com/S2>, ~I<http://example.com/p>, RDF.XSD.integer(42)}
    ...> ])
    ...> |> RDF.Graph.map(fn
    ...>      {:predicate, predicate} ->
    ...>        predicate
    ...>        |> to_string()
    ...>        |> String.split("/")
    ...>        |> List.last()
    ...>        |> String.to_atom()
    ...>      {_, term} ->
    ...>        RDF.Term.value(term)
    ...>    end)
    %{
      "http://example.com/S1" => %{p: ["Foo"]},
      "http://example.com/S2" => %{p: [42]}
    }

# `name`

```elixir
@spec name(t()) :: RDF.Star.Statement.graph_name()
```

Returns the graph name IRI of `graph`.

# `new`

```elixir
@spec new() :: t()
```

Creates an empty unnamed `RDF.Graph`.

# `new`

```elixir
@spec new(input() | keyword()) :: t()
```

Creates an `RDF.Graph`.

If a keyword list with options is given an empty graph is created.
Otherwise, an unnamed graph initialized with the given data is created.

See `new/2` for available arguments and the different ways to provide data.

When a `RDF.Dataset` is given, the created graph is the aggregation of all
the graphs of this dataset.

## Examples

    RDF.Graph.new(name: EX.GraphName)

    RDF.Graph.new(init: {EX.S, EX.p, EX.O})

    RDF.Graph.new({EX.S, EX.p, EX.O})

# `new`

```elixir
@spec new(
  input(),
  keyword()
) :: t()
```

Creates an `RDF.Graph` initialized with data.

The initial RDF triples can be provided

- as a single statement tuple
- a nested subject-predicate-object map
- a `RDF.Description`
- a `RDF.Graph`
- a `RDF.Dataset`
- or a list with any combination of the former

Available options:

- `name`: the name of the graph to be created
- `prefixes`: some prefix mappings which should be stored alongside the graph
  and will be used for example when serializing in a format with prefix support
- `base_iri`: a base IRI which should be stored alongside the graph
  and will be used for example when serializing in a format with base IRI support
- `init`: some data with which the graph should be initialized; the data can be
  provided in any form accepted by `add/3` and above that also with a function returning
  the initialization data in any of these forms

## Examples

    RDF.Graph.new({EX.S, EX.p, EX.O})
    RDF.Graph.new({EX.S, EX.p, EX.O}, name: EX.GraphName)
    RDF.Graph.new({EX.S, EX.p, [EX.O1, EX.O2]})
    RDF.Graph.new([{EX.S1, EX.p1, EX.O1}, {EX.S2, EX.p2, EX.O2}])
    RDF.Graph.new(RDF.Description.new(EX.S, EX.P, EX.O))
    RDF.Graph.new([graph, description, triple])
    RDF.Graph.new({EX.S, EX.p, EX.O}, name: EX.GraphName, base_iri: EX.base)

# `pop`

```elixir
@spec pop(t()) :: {RDF.Star.Statement.t() | nil, t()}
```

Pops an arbitrary triple from a `RDF.Graph`.

# `pop`

```elixir
@spec pop(t(), RDF.Star.Statement.coercible_subject()) ::
  {RDF.Description.t() | nil, t()}
```

Pops the description of the given subject.

Removes the description of the given `subject` from `graph`.

Returns a tuple containing the description of the given subject
and the updated graph without this description.
`nil` is returned instead of the description if `graph` does
not contain a description of the given `subject`.

## Examples

    iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
    ...> |> RDF.Graph.pop(EX.S1)
    {
      RDF.Description.new(EX.S1, init: {EX.P1, EX.O1}),
      RDF.Graph.new({EX.S2, EX.P2, EX.O2})
    }

    iex> RDF.Graph.new({EX.S, EX.P, EX.O})
    ...> |> RDF.Graph.pop(EX.Missing)
    {nil, RDF.Graph.new({EX.S, EX.P, EX.O})}

# `prefixes`

```elixir
@spec prefixes(t()) :: RDF.PrefixMap.t()
```

Returns the prefixes of the given `graph` as a `RDF.PrefixMap`.

# `prefixes`

```elixir
@spec prefixes(t(), any()) :: RDF.PrefixMap.t() | any()
```

Returns the prefixes of the given `graph` as a `RDF.PrefixMap` or returns the given default when empty.

# `put`

```elixir
@spec put(t(), input(), keyword()) :: t()
```

Adds statements to a `RDF.Graph` overwriting existing statements with the subjects given in the `input` data.

When the statements to be added are given as another `RDF.Graph`, the prefixes
of this graph will be added. In case of conflicting prefix mappings the
original prefix from `graph` will be kept.

RDF-star annotations to be added to all the given statements can be specified with
the `:add_annotations`, `:put_annotations` or `:put_annotation_properties` keyword
options. They have different addition semantics similar to the `add_annotations/3`,
`put_annotations/3` and `put_annotation_properties/3` counterparts.

What should happen with the annotations of statements which got deleted during
overwrite, can be controlled with these keyword options:

- `:delete_annotations_on_deleted`: deletes all or some annotations of the deleted
  statements (see `delete_annotations/3` on possible values)
- `:add_annotations_on_deleted`, `:put_annotations_on_deleted`,
  `:put_annotation_properties_on_deleted`: add annotations about the deleted
  statements with the respective addition semantics similar to the keyword
  options with the `_on_deleted` suffix mentioned above

## Examples

    iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
    ...> |> RDF.Graph.put([{EX.S1, EX.P3, EX.O3}])
    RDF.Graph.new([{EX.S1, EX.P3, EX.O3}, {EX.S2, EX.P2, EX.O2}])

# `put_annotation_properties`

```elixir
@spec put_annotation_properties(t(), input(), RDF.Description.input() | nil) :: t()
```

Adds RDF-star annotations to the given set of statements overwriting all existing annotations with the given properties.

The set of `statements` can be given in any input form (see `add/3`).

The predicate-objects pairs to be added as annotations can be given as a tuple,
a list of tuples or a map.

# `put_annotations`

```elixir
@spec put_annotations(t(), input(), RDF.Description.input() | nil) :: t()
```

Adds RDF-star annotations to the given set of statements overwriting all existing annotations.

The set of `statements` can be given in any input form (see `add/3`).

The predicate-objects pairs to be added as annotations can be given as a tuple,
a list of tuples or a map.

# `put_properties`

```elixir
@spec put_properties(t(), input(), keyword()) :: t()
```

Adds statements to a `RDF.Graph` and overwrites all existing statements with the same subject-predicate combinations given in the `input` data.

When the statements to be added are given as another `RDF.Graph`, the prefixes
of this graph will be added. In case of conflicting prefix mappings the
original prefix from `graph` will be kept.

RDF-star annotations to be added to all the given statements can be specified with
the `:add_annotations`, `:put_annotations` or `:put_annotation_properties` keyword
options. They have different addition semantics similar to the `add_annotations/3`,
`put_annotations/3` and `put_annotation_properties/3` counterparts.

What should happen with the annotations of statements which got deleted during
overwrite, can be controlled with these keyword options:

- `:delete_annotations_on_deleted`: deletes all or some annotations of the deleted
  statements (see `delete_annotations/3` on possible values)
- `:add_annotations_on_deleted`, `:put_annotations_on_deleted`,
  `:put_annotation_properties_on_deleted`: add annotations about the deleted
  statements with the respective addition semantics similar to the keyword
  options with the `_on_deleted` suffix mentioned above

## Examples

    iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
    ...> |> RDF.Graph.put_properties([{EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])
    RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])

# `quads`

```elixir
@spec quads(
  t(),
  keyword()
) :: [RDF.Star.Quad.t()]
```

The list of all statements within a `RDF.Graph` as quads.

When the optional `:filter_star` flag is set to `true` RDF-star triples with
a triple as subject or object will be filtered. The default value is `false`.

## Examples

      iex> RDF.Graph.new([
      ...>   {EX.S1, EX.p1, EX.O1},
      ...>   {EX.S2, EX.p2, EX.O2},
      ...>   {EX.S1, EX.p2, EX.O3}
      ...>  ], name: EX.Graph)
      ...> |> RDF.Graph.quads()
      [{RDF.iri(EX.S1), RDF.iri(EX.p1), RDF.iri(EX.O1), RDF.iri(EX.Graph)},
       {RDF.iri(EX.S1), RDF.iri(EX.p2), RDF.iri(EX.O3), RDF.iri(EX.Graph)},
       {RDF.iri(EX.S2), RDF.iri(EX.p2), RDF.iri(EX.O2), RDF.iri(EX.Graph)}]

      iex> RDF.Graph.new([
      ...>   {EX.S1, EX.p1, EX.O1},
      ...>   {EX.S2, EX.p2, EX.O2},
      ...>   {EX.S1, EX.p2, EX.O3}])
      ...> |> RDF.Graph.quads()
      [{RDF.iri(EX.S1), RDF.iri(EX.p1), RDF.iri(EX.O1), nil},
       {RDF.iri(EX.S1), RDF.iri(EX.p2), RDF.iri(EX.O3), nil},
       {RDF.iri(EX.S2), RDF.iri(EX.p2), RDF.iri(EX.O2), nil}]

# `query`

Execute the given `query` against the given `graph`.

This is just a convenience delegator function to `RDF.Query.execute!/3` with
the first two arguments swapped, so it can be used in a pipeline on a `RDF.Graph`.

See `RDF.Query.execute/3` and `RDF.Query.execute!/3` for more information and examples.

# `query_stream`

Returns a `Stream` for the execution of the given `query` against the given `graph`.

This is just a convenience delegator function to `RDF.Query.stream!/3` with
the first two arguments swapped, so it can be used in a pipeline on a `RDF.Graph`.

See `RDF.Query.stream/3` and `RDF.Query.stream!/3` for more information and examples.

# `reachable`

```elixir
@spec reachable(t(), RDF.Resource.coercible(), follow_fun() | keyword()) :: t()
```

Computes the reachable subgraph by traversing from a starting node.

This function computes a form of forward reachability closure with
configurable traversal constraints.

## Parameters

- `graph`: The RDF graph to traverse
- `resource`: The starting node for traversal (supports coercible resources like namespace terms and also RDF-star quoted triples)
- `follow_fun_or_opts`: Either a custom follow function or keyword options (optional, defaults to `follow: :all`)

## Follow Function

A custom follow function can be provided either:

- As the third argument directly: `reachable(graph, resource, follow_fun)`
- Via the `:follow` option: `reachable(graph, resource, follow: follow_fun)`

The follow function receives three parameters:
  
1. `object`: The object node of the current triple (potential next node to visit)
2. `predicate`: The predicate of the current triple
3. `depth`: Current depth of traversal (starting node has depth 0, its neighbors depth 1, etc.)

Returns `true` to follow the node, `false` to skip it.

**Note**: When providing a custom follow function directly as the third argument,
it cannot be combined with other options (except `:into`). Use the `:follow` keyword
option if you need to combine it with other options.

## Keyword Options

- `:follow` - Traversal strategy or custom function:
  - `:all` - Follow all nodes (complete reachability) (default)
  - `:bnodes` - Only follow blank nodes (similar to Concise Bounded Description)
  - custom function with arity 3 - See "Follow Function" section above
- `:max_depth` - Maximum traversal depth for all nodes (integer or `:unlimited`, default: `:unlimited`)
- `:bnode_depth` - Maximum traversal depth for blank nodes (integer or `:unlimited`, defaults to the value of `max_depth`)
- `:predicates` - List of predicates to follow (only edges with these predicates are traversed)
- `:into` - Target graph to write results into (default: empty graph)

## Examples

Complete reachability (using default):

    iex> graph = RDF.Graph.new([
    ...>   {EX.A, EX.p(), EX.B},
    ...>   {EX.B, EX.p(), EX.C},
    ...>   {EX.D, EX.p(), EX.E}
    ...> ])
    iex> RDF.Graph.reachable(graph, EX.A)
    RDF.Graph.new([
      {EX.A, EX.p(), EX.B},
      {EX.B, EX.p(), EX.C}
    ])

Only follow blank nodes (similar to Concise Bounded Description):

    iex> graph = RDF.Graph.new([
    ...>   {EX.A, EX.p(), ~B<b1>},
    ...>   {EX.A, EX.q(), EX.B},
    ...>   {~B<b1>, EX.r(), ~B<b2>},
    ...>   {EX.B, EX.s(), EX.C}
    ...> ])
    iex> RDF.Graph.reachable(graph, EX.A, follow: :bnodes)
    RDF.Graph.new([
      {EX.A, EX.p(), ~B<b1>},
      {EX.A, EX.q(), EX.B},
      {~B<b1>, EX.r(), ~B<b2>}
    ])

With maximum depth and unlimited blank nodes:

    iex> graph = RDF.Graph.new([
    ...>   {EX.A, EX.p(), EX.B},
    ...>   {EX.B, EX.p(), EX.C},
    ...>   {EX.B, EX.p(), ~B<b1>},
    ...>   {~B<b1>, EX.p(), ~B<b2>},
    ...>   {~B<b2>, EX.p(), EX.C},
    ...>   {EX.C, EX.p(), EX.D}
    ...> ])
    iex> RDF.Graph.reachable(graph, EX.A, max_depth: 1, bnode_depth: :unlimited)
    RDF.Graph.new([
      {EX.A, EX.p(), EX.B},
      {EX.B, EX.p(), EX.C},
      {EX.B, EX.p(), ~B<b1>},
      {~B<b1>, EX.p(), ~B<b2>},
      {~B<b2>, EX.p(), EX.C}
    ])

With custom follow function (as third argument):

    iex> alias RDF.NS.RDFS
    iex> graph = RDF.Graph.new([
    ...>   {EX.A, RDFS.subClassOf(), EX.B},
    ...>   {EX.A, EX.other(), EX.C},
    ...>   {EX.B, RDFS.subClassOf(), EX.D}
    ...> ])
    iex> RDF.Graph.reachable(graph, EX.A, fn _obj, pred, depth ->
    ...>   pred == RDFS.subClassOf() and depth <= 2
    ...> end)
    RDF.Graph.new([
      {EX.A, RDFS.subClassOf(), EX.B},
      {EX.A, EX.other(), EX.C},
      {EX.B, RDFS.subClassOf(), EX.D}
    ])

Writing into an existing graph:

    iex> target = RDF.Graph.new({EX.Existing, EX.p(), EX.O}, name: EX.MyGraph)
    iex> graph = RDF.Graph.new([
    ...>   {EX.A, EX.p(), EX.B},
    ...>   {EX.B, EX.p(), EX.C}
    ...> ])
    iex> RDF.Graph.reachable(graph, EX.A, into: target)
    RDF.Graph.new([
      {EX.Existing, EX.p(), EX.O},
      {EX.A, EX.p(), EX.B},
      {EX.B, EX.p(), EX.C}
    ], name: EX.MyGraph)

# `rename_resource`

```elixir
@spec rename_resource(t(), RDF.Resource.coercible(), RDF.Resource.coercible()) :: t()
```

Replaces all occurrences of `old_id` in `graph` with `new_id`.

## Examples

    iex> RDF.Graph.new([
    ...>  {EX.S, EX.p, ~B<bnode>},
    ...>  {~B<bnode>, EX.p, [EX.O, EX.S]}])
    ...> |> RDF.Graph.rename_resource(EX.S, EX.New)
    ...> |> RDF.Graph.rename_resource(~B<bnode>, EX.Skolemized)
    [
      EX.New |> EX.p(EX.Skolemized),
      EX.Skolemized |> EX.p([EX.O, EX.New])
    ] |> RDF.Graph.new()

# `set_base_iri`

```elixir
@spec set_base_iri(t(), RDF.IRI.t() | nil) :: t()
```

Sets the base IRI of the given `graph`.

The `base_iri` can be given as anything accepted by `RDF.IRI.coerce_base/1`.

# `statement_count`

```elixir
@spec statement_count(t()) :: non_neg_integer()
```

The number of statements within a `RDF.Graph`.

## Examples

    iex> RDF.Graph.new([
    ...>   {EX.S1, EX.p1, EX.O1},
    ...>   {EX.S2, EX.p2, EX.O2},
    ...>   {EX.S1, EX.p2, EX.O3}])
    ...> |> RDF.Graph.statement_count()
    3

# `statements`

# `subject_count`

```elixir
@spec subject_count(t()) :: non_neg_integer()
```

The number of subjects within a `RDF.Graph`.

## Examples

    iex> RDF.Graph.new([
    ...>   {EX.S1, EX.p1, EX.O1},
    ...>   {EX.S2, EX.p2, EX.O2},
    ...>   {EX.S1, EX.p2, EX.O3}])
    ...> |> RDF.Graph.subject_count()
    2

# `subjects`

The set of all subjects used in the statements within a `RDF.Graph`.

## Examples

    iex> RDF.Graph.new([
    ...>   {EX.S1, EX.p1, EX.O1},
    ...>   {EX.S2, EX.p2, EX.O2},
    ...>   {EX.S1, EX.p2, EX.O3}])
    ...> |> RDF.Graph.subjects()
    MapSet.new([RDF.iri(EX.S1), RDF.iri(EX.S2)])

# `take`

```elixir
@spec take(
  t(),
  [RDF.Star.Statement.coercible_subject()] | Enum.t() | nil,
  [RDF.Star.Statement.coercible_predicate()] | Enum.t() | nil
) :: t()
```

Creates a graph from another one by limiting its statements to those using one of the given `subjects`.

If `subjects` contains IRIs that are not used in the `graph`, they're simply ignored.

The optional `properties` argument allows to limit also properties of the subject descriptions.

If `nil` is passed as the `subjects`, the subjects will not be limited.

# `triple_count`

# `triples`

```elixir
@spec triples(
  t(),
  keyword()
) :: [RDF.Star.Triple.t()]
```

The list of all statements within a `RDF.Graph`.

When the optional `:filter_star` flag is set to `true` RDF-star triples with
a triple as subject or object will be filtered. The default value is `false`.

## Examples

      iex> RDF.Graph.new([
      ...>   {EX.S1, EX.p1, EX.O1},
      ...>   {EX.S2, EX.p2, EX.O2},
      ...>   {EX.S1, EX.p2, EX.O3}])
      ...> |> RDF.Graph.triples()
      [{RDF.iri(EX.S1), RDF.iri(EX.p1), RDF.iri(EX.O1)},
       {RDF.iri(EX.S1), RDF.iri(EX.p2), RDF.iri(EX.O3)},
       {RDF.iri(EX.S2), RDF.iri(EX.p2), RDF.iri(EX.O2)}]

# `update`

```elixir
@spec update(
  t(),
  RDF.Star.Statement.coercible_subject(),
  RDF.Description.input() | nil,
  update_description_fun()
) :: t()
```

Updates the description of the `subject` in `graph` with the given function.

If `subject` is present in `graph` with `description` as description,
`fun` is invoked with argument `description` and its result is used as the new
description of `subject`. If `subject` is not present in `graph`,
`initial` is inserted as the description of `subject`. If no `initial` value is
given, the `graph` remains unchanged. If `nil` is returned by `fun`, the
respective description will be removed from `graph`.

The initial value and the returned objects by the update function will be
coerced to proper RDF descriptions before added. If the initial or returned
description is a `RDF.Description` with another subject, the respective
statements are added with `subject` as subject.

## Examples

    iex> RDF.Graph.new({EX.S, EX.p, EX.O})
    ...> |> RDF.Graph.update(EX.S,
    ...>      fn description -> Description.add(description, {EX.p, EX.O2})
    ...>    end)
    RDF.Graph.new([{EX.S, EX.p, EX.O}, {EX.S, EX.p, EX.O2}])
    iex> RDF.Graph.new({EX.S, EX.p, EX.O})
    ...> |> RDF.Graph.update(EX.S,
    ...>      fn _ -> Description.new(EX.S2, init: {EX.p2, EX.O2})
    ...>    end)
    RDF.Graph.new([{EX.S, EX.p2, EX.O2}])
    iex> RDF.Graph.new()
    ...> |> RDF.Graph.update(EX.S, Description.new(EX.S, init: {EX.p, EX.O}),
    ...>      fn description -> Description.add(description, {EX.p, EX.O2})
    ...>    end)
    RDF.Graph.new([{EX.S, EX.p, EX.O}])

# `update_all_descriptions`

```elixir
@spec update_all_descriptions(t(), update_description_fun()) :: t()
```

Updates all descriptions in `graph` with the given function.

The same behaviour as described in `RDF.Graph.update/4` apply.
If `nil` is returned by `fun`, the respective description will be removed from `graph`.
The returned values by the update function will be coerced to proper RDF descriptions before added.
If the returned description is a `RDF.Description` with another subject, it will still be added
using the old subject.

## Examples

    iex> RDF.Graph.new([{EX.S1, EX.p1, EX.O1}, {EX.S2, EX.p2, EX.O2}])
    ...> |> RDF.Graph.update_all_descriptions(&(&1 |> EX.foo(42)))
    [
      EX.S1 |> EX.p1(EX.O1) |> EX.foo(42),
      EX.S2 |> EX.p2(EX.O2) |> EX.foo(42)
    ] |> RDF.Graph.new()

# `values`

```elixir
@spec values(
  t(),
  keyword()
) :: map()
```

Returns a nested map of the native Elixir values of a `RDF.Graph`.

When a `:context` option is given with a `RDF.PropertyMap`, predicates will
be mapped to the terms defined in the `RDF.PropertyMap`, if present.

## Examples

    iex> RDF.Graph.new([
    ...>   {~I<http://example.com/S1>, ~I<http://example.com/p>, ~L"Foo"},
    ...>   {~I<http://example.com/S2>, ~I<http://example.com/p>, RDF.XSD.integer(42)}
    ...> ])
    ...> |> RDF.Graph.values()
    %{
      "http://example.com/S1" => %{"http://example.com/p" => ["Foo"]},
      "http://example.com/S2" => %{"http://example.com/p" => [42]}
    }

    iex> RDF.Graph.new([
    ...>   {~I<http://example.com/S1>, ~I<http://example.com/p>, ~L"Foo"},
    ...>   {~I<http://example.com/S2>, ~I<http://example.com/p>, RDF.XSD.integer(42)}
    ...> ])
    ...> |> RDF.Graph.values(context: [p: ~I<http://example.com/p>])
    %{
      "http://example.com/S1" => %{p: ["Foo"]},
      "http://example.com/S2" => %{p: [42]}
    }

# `without_annotations`

```elixir
@spec without_annotations(t()) :: t()
```

Returns the `RDF.Graph` without all annotations.

Note: This function excludes only triples where the subject is a quoted triple.
If you want to exclude also triples where the object is a quoted triple,
you'll have to use `RDF.Graph.without_star_statements/1`.

# `without_star_statements`

```elixir
@spec without_star_statements(t()) :: t()
```

Returns the `RDF.Graph` without all statements including quoted triples on subject or object position.

This function is relatively costly, since it requires a full walk-through of all triples.
In many cases quoted triples are only used on subject position, where you can use
the significantly faster `RDF.Graph.without_annotations/1`.

---

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