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

A behaviour for datatypes for `RDF.Literal`s.

An implementation of this behaviour defines a struct for a datatype IRI and the semantics of its
values via the functions defined by this behaviour.

There are three important groups of `RDF.Literal.Datatype` implementations:

- `RDF.XSD.Datatype`: This is another, more specific behaviour for XSD datatypes. RDF.ex comes with
  builtin implementations of this behaviour for the most important XSD datatypes, but you define
  your own custom datatypes by deriving from these builtin datatypes and constraining them via
  `RDF.XSD.Facet`s.
- Non-XSD datatypes which implement the `RDF.Literal.Datatype` directly.
  There's currently only two builtin datatypes of this category
    - `RDF.LangString` for language tagged RDF literals and
    - `RDF.JSON` for JSON content
- `RDF.Literal.Generic`: This is a generic implementation which is used for `RDF.Literal`s with a
  datatype that has no own `RDF.Literal.Datatype` implementation defining its semantics.

# `comparison_result`

```elixir
@type comparison_result() :: :lt | :gt | :eq
```

# `literal`

```elixir
@type literal() :: %{:__struct__ =&gt; t(), optional(atom()) =&gt; any()}
```

# `t`

```elixir
@type t() :: module()
```

# `canonical`

```elixir
@callback canonical(RDF.Literal.t() | literal()) :: RDF.Literal.t()
```

Produces the canonical representation of a `RDF.Literal`.

# `canonical?`

```elixir
@callback canonical?(RDF.Literal.t() | literal() | any()) :: boolean()
```

Determines if the lexical form of a `RDF.Literal` is the canonical form.

Note: For `RDF.Literal.Generic` literals with the canonical form not defined,
this always returns `true`.

# `canonical_lexical`

```elixir
@callback canonical_lexical(RDF.Literal.t() | literal()) :: String.t() | nil
```

Returns the canonical lexical form of a `RDF.Literal`.

If the given literal is invalid, `nil` is returned.

# `datatype?`

```elixir
@callback datatype?(RDF.Literal.t() | t() | literal()) :: boolean()
```

Checks if the given `RDF.Literal` has the datatype for which the `RDF.Literal.Datatype` is implemented or is derived from it.

## Example

    iex> RDF.XSD.byte(42) |> RDF.XSD.Integer.datatype?()
    true

# `datatype_id`

```elixir
@callback datatype_id(RDF.Literal.t() | literal()) :: RDF.IRI.t()
```

The datatype IRI of the given `RDF.Literal`.

# `do_cast`

```elixir
@callback do_cast(literal() | RDF.IRI.t() | RDF.BlankNode.t()) :: RDF.Literal.t() | nil
```

Callback for datatype specific castings.

This callback is called by the auto-generated `cast/1` function on the implementations, which already deals with the basic cases.
So, implementations can assume the passed argument is a valid `RDF.Literal.Datatype` struct,
a `RDF.IRI` or a `RDF.BlankNode`.

If the given literal can not be converted into this datatype an implementation should return `nil`.

A final catch-all clause should delegate to `super`. For example `RDF.XSD.Datatype`s will handle casting from derived
datatypes in the default implementation.

# `do_compare`

```elixir
@callback do_compare(literal() | any(), literal() | any()) ::
  comparison_result() | :indeterminate | nil
```

Callback for datatype specific `compare/2` comparisons between two `RDF.Literal`s.

This callback is called by auto-generated `compare/2` function on the implementations, which already deals with the basic cases.
So, implementations can assume the passed arguments are valid `RDF.Literal.Datatype` structs and
have the same datatypes or are derived from each other.

Should return `:gt` if value of the first literal is greater than the value of the second in
terms of their datatype and `:lt` for vice versa. If the two literals can be considered equal `:eq` should be returned.
For datatypes with only partial ordering `:indeterminate` should be returned when the
order of the given literals is not defined.

`nil` should be returned when the given arguments are not comparable datatypes or if one them is invalid.

The default implementation of the `_using__` macro of `RDF.Literal.Datatype`s
just compares the values of the given literals.

# `do_equal_value_different_datatypes?`

```elixir
@callback do_equal_value_different_datatypes?(literal(), literal()) :: boolean() | nil
```

Callback for datatype specific `equal_value?/2` comparisons when the given literals have different datatypes.

This callback is called by auto-generated `equal_value?/2` function when the given literals have
different datatypes and are not derived from each other.

Should return `nil` when the given arguments are not comparable as literals of this
datatype. This behaviour is particularly important for SPARQL.ex where this
function is used for the `=` operator, where comparisons between incomparable
terms are treated as errors and immediately leads to a rejection of a possible
match.

See also `c:do_equal_value_same_or_derived_datatypes?/2`.

# `do_equal_value_same_or_derived_datatypes?`

```elixir
@callback do_equal_value_same_or_derived_datatypes?(literal(), literal()) ::
  boolean() | nil
```

Callback for datatype specific `equal_value?/2` comparisons when the given literals have the same or derived datatypes.

This callback is called by auto-generated `equal_value?/2` function when the given literals have
the same datatype or one is derived from the other.

Should return `nil` when the given arguments are not comparable as literals of this
datatype. This behaviour is particularly important for SPARQL.ex where this
function is used for the `=` operator, where comparisons between incomparable
terms are treated as errors and immediately leads to a rejection of a possible
match.

See also `c:do_equal_value_different_datatypes?/2`.

# `id`

```elixir
@callback id() :: RDF.IRI.t() | nil
```

The IRI of the datatype.

# `language`

```elixir
@callback language(RDF.Literal.t() | literal()) :: String.t() | nil
```

The language of the given `RDF.Literal` if present.

# `lexical`

```elixir
@callback lexical(RDF.Literal.t() | literal()) :: String.t()
```

Returns the lexical form of a `RDF.Literal`.

# `name`

```elixir
@callback name() :: String.t()
```

The name of the datatype.

# `new`

```elixir
@callback new(any()) :: RDF.Literal.t()
```

# `new`

```elixir
@callback new(any(), Keyword.t()) :: RDF.Literal.t()
```

# `new!`

```elixir
@callback new!(any()) :: RDF.Literal.t()
```

# `new!`

```elixir
@callback new!(any(), Keyword.t()) :: RDF.Literal.t()
```

# `update`

```elixir
@callback update(RDF.Literal.t() | literal(), fun()) :: RDF.Literal.t()
```

Updates the value of a `RDF.Literal` without changing everything else.

## Example

    iex> RDF.XSD.integer(42) |> RDF.XSD.Integer.update(fn value -> value + 1 end)
    RDF.XSD.integer(43)
    iex> ~L"foo"de |> RDF.LangString.update(fn _ -> "bar" end)
    ~L"bar"de
    iex> RDF.literal("foo", datatype: "http://example.com/dt") |> RDF.Literal.Generic.update(fn _ -> "bar" end)
    RDF.literal("bar", datatype: "http://example.com/dt")

# `update`

```elixir
@callback update(RDF.Literal.t() | literal(), fun(), keyword()) :: RDF.Literal.t()
```

Updates the value of a `RDF.Literal` without changing anything else.

This variant of `c:update/2` allows with the `:as` option to specify what will
be passed to `fun`, e.g. with `as: :lexical` the lexical is passed to the function.

## Example

    iex> RDF.XSD.integer(42) |> RDF.XSD.Integer.update(
    ...>   fn value -> value <> "1" end, as: :lexical)
    RDF.XSD.integer(421)

# `valid?`

```elixir
@callback valid?(RDF.Literal.t() | literal() | any()) :: boolean()
```

Determines if a `RDF.Literal` has a proper value of the value space of its datatype.

This function also accepts literals of derived datatypes.

# `value`

```elixir
@callback value(RDF.Literal.t() | literal()) :: any()
```

Returns the value of a `RDF.Literal`.

This function also accepts literals of derived datatypes.

# `get`

Returns the `RDF.Literal.Datatype` for a datatype IRI.

---

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