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

A bidirectional mapping from atom names to `RDF.IRI`s of properties.

These mappings can be used in all functions of the RDF data structures
to provide the meaning of the predicate terms in input statements or
define how the IRIs of predicates should be mapped with the value mapping
functions like `RDF.Description.values/2` etc.
The `:context` option of these functions either take a `RDF.PropertyMap` directly
or anything from which a `RDF.PropertyMap` can be created with `new/1`.

Because the mapping is bidirectional each term and IRI can be used only in
one mapping of a `RDF.PropertyMap`.

This module implements the `Enumerable` protocol and the `Access` behaviour.

# `coercible_term`

```elixir
@type coercible_term() :: atom() | String.t()
```

# `input`

```elixir
@type input() ::
  t() | map() | keyword() | RDF.Namespace.t() | RDF.Vocabulary.Namespace.t()
```

# `t`

```elixir
@type t() :: %RDF.PropertyMap{
  iris: %{required(atom()) =&gt; RDF.IRI.t()},
  terms: %{required(RDF.IRI.t()) =&gt; atom()}
}
```

# `add`

```elixir
@spec add(t(), input()) :: {:ok, t()} | {:error, String.t()}
```

Adds a set of property mappings to `property_map`.

The mappings can be passed in various ways:

- as keyword lists or maps where terms for the RDF properties can
  be given as atoms or strings, while the property IRIs can be given as
  `RDF.IRI`s or strings
- a strict `RDF.Vocabulary.Namespace` from which all lowercase terms are added
  with their respective IRI; since IRIs can also be once in a
  `RDF.PropertyMap` a defined alias term is preferred over an original term
- a `RDF.Namespace` from which all lowercase terms are added
  with their respective IRI
- another `RDF.PropertyMap` from which all mappings are merged

Unless a mapping for any of the terms or IRIs in the `input` already exists,
an `:ok` tuple is returned, otherwise an `:error` tuple.

# `add`

```elixir
@spec add(t(), coercible_term(), RDF.IRI.coercible()) ::
  {:ok, t()} | {:error, String.t()}
```

Adds a property mapping between `term` and `iri` to `property_map`.

Unless another mapping for `term` or `iri` already exists, an `:ok` tuple
is returned, otherwise an `:error` tuple.

# `add!`

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

Adds a set of property mappings to `property_map` and raises an error on conflicts.

See `add/2` for the different forms in which mappings can be provided.

# `delete`

```elixir
@spec delete(t(), coercible_term()) :: t()
```

Deletes the property mapping for `term` from `property_map`.

If no mapping for `term` exists, `property_map` is returned unchanged.

# `drop`

```elixir
@spec drop(t(), [coercible_term()]) :: t()
```

Drops the given `terms` from the `property_map`.

If `terms` contains terms that are not in `property_map`, they're simply ignored.

# `iri`

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

Returns the IRI for the given `term` in `property_map`.

Returns `nil`, when the given `term` is not present in `property_map`.

# `iri_defined?`

```elixir
@spec iri_defined?(t(), coercible_term()) :: boolean()
```

Returns whether a mapping for the given `term` is defined in `property_map`.

# `iris`

```elixir
@spec iris(t()) :: [RDF.IRI.t()]
```

Returns the list of all IRIs in the given `property_map`.

# `new`

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

Creates an empty `RDF.PropertyMap`.

# `new`

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

Creates a new `RDF.PropertyMap` with initial mappings.

See `add/2` for the different forms in which mappings can be provided.

# `put`

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

Adds a set of property mappings to `property_map` overwriting all existing mappings.

See `add/2` for the different forms in which mappings can be provided.

Note, that not just all mappings with the used terms in the input `mappings`
are overwritten, but also all mappings with IRIs in the input `mappings`

# `put`

```elixir
@spec put(t(), coercible_term(), RDF.IRI.coercible()) :: t()
```

Adds a property mapping between `term` and `iri` to `property_map` overwriting existing mappings.

# `term`

```elixir
@spec term(t(), RDF.IRI.coercible()) :: atom() | nil
```

Returns the term for the given `namespace` in `prefix_map`.

Returns `nil`, when the given `namespace` is not present in `prefix_map`.

# `term_defined?`

```elixir
@spec term_defined?(t(), RDF.IRI.coercible()) :: boolean()
```

Returns whether a mapping for the given `iri` is defined in `property_map`.

# `terms`

```elixir
@spec terms(t()) :: [atom()]
```

Returns the list of all terms in the given `property_map`.

# `to_list`

```elixir
@spec to_list(t()) :: [{atom(), RDF.IRI.t()}]
```

Converts property map to a list.

Each term-IRI pair in the property map is converted to a two-element tuple
`{term, iri}` in the resulting list.

## Examples

    iex> RDF.PropertyMap.new(foo: "http://example.com/foo") |> RDF.PropertyMap.to_list()
    [foo: ~I<http://example.com/foo>]

# `to_sorted_list`

```elixir
@spec to_sorted_list(t()) :: [{atom(), RDF.IRI.t()}]
```

Converts property map to a list sorted by property.

Each term-IRI pair in the property map is converted to a two-element tuple
`{term, iri}` in the resulting list.

## Examples

    iex> RDF.PropertyMap.new(
    ...>   foo: "http://example.com/foo",
    ...>   bar: "http://example.com/bar")
    ...> |> RDF.PropertyMap.to_sorted_list()
    [bar: ~I<http://example.com/bar>, foo: ~I<http://example.com/foo>]

---

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