Update API documentation

This commit is contained in:
Marcel Otto 2020-06-01 15:43:38 +02:00
parent 21924315cc
commit fab63e6a0d
12 changed files with 344 additions and 16 deletions

View file

@ -252,10 +252,15 @@ defmodule RDF do
for term <- ~w[type subject predicate object first rest value]a do
defdelegate unquote(term)(), to: RDF.NS.RDF
@doc false
defdelegate unquote(term)(s, o), to: RDF.NS.RDF
@doc false
defdelegate unquote(term)(s, o1, o2), to: RDF.NS.RDF
@doc false
defdelegate unquote(term)(s, o1, o2, o3), to: RDF.NS.RDF
@doc false
defdelegate unquote(term)(s, o1, o2, o3, o4), to: RDF.NS.RDF
@doc false
defdelegate unquote(term)(s, o1, o2, o3, o4, o5), to: RDF.NS.RDF
end

View file

@ -1,6 +1,10 @@
defmodule RDF.Literal do
@moduledoc """
RDF literals are leaf nodes of a RDF graph containing raw data, like strings and numbers.
RDF literals are leaf nodes of a RDF graph containing raw data, like strings, numbers etc.
A literal is a struct consisting of a `literal` field holding either a `RDF.Literal.Datatype` struct
for the respective known datatype of the literal or a `RDF.Literal.Generic` struct if the datatype
is unknown, i.e. has no `RDF.Literal.Datatype` implementation.
"""
defstruct [:literal]
@ -238,34 +242,66 @@ defmodule RDF.Literal do
############################################################################
# functions delegating to the RDF.Literal.Datatype of a RDF.Literal
@doc """
Returns the IRI of datatype of the given `literal`.
"""
@spec datatype_id(t) :: IRI.t()
def datatype_id(%__MODULE__{literal: %datatype{} = literal}), do: datatype.datatype_id(literal)
@doc """
Returns the language of the given `literal` if present.
"""
@spec language(t) :: String.t() | nil
def language(%__MODULE__{literal: %datatype{} = literal}), do: datatype.language(literal)
@doc """
Returns the value of the given `literal`.
"""
@spec value(t) :: any
def value(%__MODULE__{literal: %datatype{} = literal}), do: datatype.value(literal)
@doc """
Returns the lexical form of the given `literal`.
"""
@spec lexical(t) :: String.t
def lexical(%__MODULE__{literal: %datatype{} = literal}), do: datatype.lexical(literal)
@doc """
Transforms the given `literal` into its canonical form.
"""
@spec canonical(t) :: t
def canonical(%__MODULE__{literal: %datatype{} = literal}), do: datatype.canonical(literal)
@doc """
Returns the canonical lexical of the given `literal`.
"""
@spec canonical_lexical(t) :: String.t | nil
def canonical_lexical(%__MODULE__{literal: %datatype{} = literal}), do: datatype.canonical_lexical(literal)
@doc """
Returns if the lexical of the given `literal` has the canonical form.
"""
@spec canonical?(t) :: boolean
def canonical?(%__MODULE__{literal: %datatype{} = literal}), do: datatype.canonical?(literal)
@doc """
Returns if the given `literal` is valid with respect to its datatype.
"""
@spec valid?(t | any) :: boolean
def valid?(%__MODULE__{literal: %datatype{} = literal}), do: datatype.valid?(literal)
def valid?(_), do: false
@doc """
Checks if two literals are equal.
Two literals are equal if they have the same datatype, value and lexical form.
"""
@spec equal?(any, any) :: boolean
def equal?(left, right), do: left == right
@doc """
Checks if two literals have equal values.
"""
@spec equal_value?(t, t | any) :: boolean
def equal_value?(%__MODULE__{literal: %datatype{} = left}, right),
do: datatype.equal_value?(left, right)
@ -314,6 +350,24 @@ defmodule RDF.Literal do
def matches?(value, pattern, flags) when is_binary(value) and is_binary(pattern) and is_binary(flags),
do: RDF.XSD.Utils.Regex.matches?(value, pattern, flags)
@doc """
Updates the value of a `RDF.Literal` without changing everything else.
The optional second argument allows to specify what will be passed to `fun` with the `:as` option,
eg. with `as: :lexical` the lexical is passed to the function.
## Example
iex> RDF.XSD.integer(42) |> RDF.Literal.update(fn value -> value + 1 end)
RDF.XSD.integer(43)
iex> ~L"foo"de |> RDF.Literal.update(fn _ -> "bar" end)
~L"bar"de
iex> RDF.literal("foo", datatype: "http://example.com/dt") |> RDF.Literal.update(fn _ -> "bar" end)
RDF.literal("bar", datatype: "http://example.com/dt")
iex> RDF.XSD.integer(42) |> RDF.XSD.Integer.update(
...> fn value -> value <> "1" end, as: :lexical)
RDF.XSD.integer(421)
"""
def update(%__MODULE__{literal: %datatype{} = literal}, fun, opts \\ []) do
datatype.update(literal, fun, opts)
end

View file

@ -1,4 +1,22 @@
defmodule RDF.Literal.Datatype do
@moduledoc """
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 one
builtin datatype of this category - `RDF.LangString` for language tagged RDF literals.
- `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.
"""
alias RDF.{Literal, IRI}
@type t :: module
@ -91,7 +109,7 @@ defmodule RDF.Literal.Datatype do
@callback canonical?(Literal.t() | literal | any) :: boolean
@doc """
Determines if the lexical form of a `RDF.Literal` is a member of its lexical value space.
Determines if a `RDF.Literal` has a proper value of the value space of its datatype.
This function also accepts literals of derived datatypes.
"""
@ -154,16 +172,16 @@ defmodule RDF.Literal.Datatype do
## Example
iex> RDF.XSD.integer(42) |> RDF.XSD.Integer.update(fn value -> value + 1 end)
RDF.XSD.integer(42)
iex> RDF.literal("foo", language: "de") |> RDF.LangString.update(fn _ -> "bar" end)
RDF.literal("bar", language: "de")
iex> RDF.literal("foo", datatype: "http://example.com/dt") |> RDF.LangString.update(fn _ -> "bar" 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")
"""
@callback update(Literal.t() | literal, fun()) :: Literal.t
@doc """
Updates the value of a `RDF.Literal` without changing everything else.
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`, eg. with `as: :lexical` the lexical is passed to the function.
@ -171,11 +189,14 @@ defmodule RDF.Literal.Datatype do
## Example
iex> RDF.XSD.integer(42) |> RDF.XSD.Integer.update(
...> fn value -> value <> "1" end, as: lexical)
...> fn value -> value <> "1" end, as: :lexical)
RDF.XSD.integer(421)
"""
@callback update(Literal.t() | literal, fun(), keyword) :: Literal.t
@doc """
Returns the `RDF.Literal.Datatype` for a datatype IRI.
"""
defdelegate get(id), to: Literal.Datatype.Registry, as: :datatype
@doc !"""
@ -223,6 +244,9 @@ defmodule RDF.Literal.Datatype do
# RDF.XSD.Datatypes offers another default implementation, but since it is
# still in a macro implementation defoverridable doesn't work
unless RDF.XSD.Datatype in @behaviour do
@doc """
Checks if the given literal has this datatype.
"""
@impl unquote(__MODULE__)
def datatype?(%Literal{literal: literal}), do: datatype?(literal)
def datatype?(%datatype{}), do: datatype?(datatype)
@ -238,6 +262,9 @@ defmodule RDF.Literal.Datatype do
def language(%Literal{literal: literal}), do: language(literal)
def language(%__MODULE__{}), do: nil
@doc """
Returns the canonical lexical form of a `RDF.Literal` of this datatype.
"""
@impl unquote(__MODULE__)
def canonical_lexical(literal)
def canonical_lexical(%Literal{literal: literal}), do: canonical_lexical(literal)
@ -255,7 +282,7 @@ defmodule RDF.Literal.Datatype do
Returns `nil` when the given arguments are not castable into this datatype or when the given argument is an
invalid literal.
Implementations define the casting for a given value with the `c:do_cast/1` callback.
Implementations define the casting for a given value with the `c:RDF.Literal.Datatype.do_cast/1` callback.
"""
@spec cast(Literal.Datatype.literal | RDF.Term.t) :: Literal.t() | nil
@dialyzer {:nowarn_function, cast: 1}
@ -290,8 +317,8 @@ defmodule RDF.Literal.Datatype do
Invalid literals are only considered equal in this relation when both have the exact same
datatype and the same attributes (lexical form, language etc.).
Implementations can customize this equivalence relation via the `c:do_equal_value_different_datatypes?/2`
and `c:do_equal_value_different_datatypes?/2` callbacks.
Implementations can customize this equivalence relation via the `c:RDF.Literal.Datatype.do_equal_value_different_datatypes?/2`
and `c:RDF.Literal.Datatype.do_equal_value_different_datatypes?/2` callbacks.
"""
def equal_value?(left, right)
def equal_value?(left, %Literal{literal: right}), do: equal_value?(left, right)
@ -382,6 +409,9 @@ defmodule RDF.Literal.Datatype do
do_compare: 2
end
@doc """
Updates the value of a `RDF.Literal` without changing everything else.
"""
@impl unquote(__MODULE__)
def update(literal, fun, opts \\ [])
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
@ -420,6 +450,8 @@ defmodule RDF.Literal.Datatype do
defimpl_ex Registration, unquote(unquoted_id),
for: RDF.Literal.Datatype.Registry.Registration do
@moduledoc false
def datatype(id), do: unquote(datatype)
end
end

View file

@ -1,5 +1,7 @@
import ProtocolEx
defprotocol_ex RDF.Literal.Datatype.Registry.Registration do
@moduledoc false
def datatype(id), do: nil
end

View file

@ -19,6 +19,9 @@ defmodule RDF.LangString do
language: String.t
}
@doc """
Creates a new `RDF.Literal` with this datatype and the given `value` and `language`.
"""
@impl RDF.Literal.Datatype
@spec new(any, String.t | atom | keyword) :: Literal.t
def new(value, language_or_opts \\ [])

View file

@ -2,7 +2,17 @@ defmodule RDF.XSD do
@moduledoc """
An implementation of the XML Schema (XSD) datatype system for use within `RDF.Literal.Datatype` system.
see <https://www.w3.org/TR/xmlschema-2/>
It consists of
- `RDF.XSD.Datatype`: a more specialized `RDF.Literal.Datatype` behaviour for XSD datatypes
- `RDF.XSD.Datatype.Primitive`: macros for the definition of `RDF.Literal.Datatype` and
`RDF.XSD.Datatype` implementations for primitive XSD datatypes
- `RDF.XSD.Datatype.Restriction`: macros for the definition of `RDF.Literal.Datatype` and
`RDF.XSD.Datatype` implementations for derived XSD datatypes
- `RDF.XSD.Facet`: a behaviour for XSD facets which can be used to constrain values on
datatype derivations
see <https://www.w3.org/TR/xmlschema11-2/>
"""
import RDF.Utils.Guards
@ -22,6 +32,10 @@ defmodule RDF.XSD do
@facets_by_name Map.new(@facets, fn facet -> {facet.name(), facet} end)
@doc """
Get a `RDF.XSD.Facet` by its name.
"""
def facet(name)
def facet(name) when is_ordinary_atom(name), do: @facets_by_name[to_string(name)]
def facet(name), do: @facets_by_name[name]

View file

@ -1,6 +1,71 @@
defmodule RDF.XSD.Datatype do
@moduledoc """
The behaviour of all XSD datatypes.
A behaviour for XSD datatypes.
A XSD datatype has three properties:
- A _value space_, which is a set of values.
- A _lexical space_, which is a set of _literals_ used to denote the values.
- A collection of functions associated with the datatype.
### Builtin XSD datatypes
RDF.ex comes with the following builtin implementations of XSD datatypes:
| `xsd:boolean` | `RDF.XSD.Boolean` |
| `xsd:float` | `RDF.XSD.Float` |
| `xsd:double` | `RDF.XSD.Double` |
| `xsd:decimal` | `RDF.XSD.Decimal` |
| `xsd:integer` | `RDF.XSD.Integer` |
| `xsd:long` | `RDF.XSD.Long` |
| `xsd:int` | `RDF.XSD.Int` |
| `xsd:short` | `RDF.XSD.Short` |
| `xsd:byte` | `RDF.XSD.Byte` |
| `xsd:nonPositiveInteger` | `RDF.XSD.NonPositiveInteger` |
| `xsd:negativeInteger` | `RDF.XSD.NegativeInteger` |
| `xsd:nonNegativeInteger` | `RDF.XSD.NonNegativeInteger` |
| `xsd:positiveInteger` | `RDF.XSD.PositiveInteger` |
| `xsd:unsignedLong` | `RDF.XSD.UnsignedLong` |
| `xsd:unsignedInt` | `RDF.XSD.UnsignedInt` |
| `xsd:unsignedShort` | `RDF.XSD.UnsignedShort` |
| `xsd:unsignedByte` | `RDF.XSD.UnsignedByte` |
| `xsd:string` | `RDF.XSD.String` |
| `xsd:normalizedString` | |
| `xsd:token` | |
| `xsd:language` | |
| `xsd:Name` | |
| `xsd:NCName` | |
| `xsd:ID` | |
| `xsd:IDREF` | |
| `xsd:ENTITY` | |
| `xsd:NMTOKEN` | |
| `xsd:dateTime` | `RDF.XSD.DateTime` |
| `xsd:dateTimeStamp` | |
| `xsd:date` | `RDF.XSD.Date` |
| `xsd:time` | `RDF.XSD.Time` |
| `xsd:duration` | |
| `xsd:dayTimeDuration` | |
| `xsd:yearMonthDuration` | |
| `xsd:gYearMonth` | |
| `xsd:gYear` | |
| `xsd:gMonthDay` | |
| `xsd:gDay` | |
| `xsd:gMonth` | |
| `xsd:base64Binary` | |
| `xsd:hexBinary` | |
| `xsd:anyURI` | `RDF.XSD.AnyURI` |
| `xsd:QName` | |
| `xsd:NOTATION` | |
There are some notable difference in the implementations of some datatypes compared to
the original spec:
- `RDF.XSD.Integer` is not derived from `RDF.XSD.Decimal`, but implemented as a primitive datatype
- `RDF.XSD.Float` is not implemented as a primitive datatype, but derived from `RDF.XSD.Double`
without further restrictions instead, since Erlang doesn't have a corresponding datatype
see <https://www.w3.org/TR/xmlschema11-2/#built-in-datatypes>
"""
@type t :: module
@ -22,6 +87,10 @@ defmodule RDF.XSD.Datatype do
@doc """
The base datatype from which a `RDF.XSD.Datatype` is derived.
Note: Since this library focuses on atomic types and the special `xsd:anyAtomicType`
specified as the base type of all primitive types in the W3C spec wouldn't serve any
purpose here, all primitive datatypes just return `nil` instead.
"""
@callback base :: t() | nil
@ -52,6 +121,17 @@ defmodule RDF.XSD.Datatype do
@doc """
A mapping from Elixir values into the value space of a `RDF.XSD.Datatype`.
If the Elixir mapping for the given value can not be mapped into value space of
the XSD datatype an implementation should return `@invalid_value`
(which is just `nil` at the moment, so `nil` is never a valid value of a value space).
Otherwise a tuple `{value, lexical}` with `value` being the internal representation
of the mapped value from the value space and `lexical` being the lexical representation
to be used for the Elixir value or `nil` if `c:init_valid_lexical/3` should be used
to determine the lexical form in general (i.e. also when initialized with a string
via the `c:lexical_mapping/2`). Since the later case is most often what you want,
you can also return `value` directly, as long as it is not a two element tuple.
"""
@callback elixir_mapping(any, Keyword.t()) :: any | {any, uncanonical_lexical}
@ -61,18 +141,34 @@ defmodule RDF.XSD.Datatype do
@callback canonical_mapping(any) :: String.t()
@doc """
Produces the lexical representation to be used as for a `RDF.XSD.Datatype` literal.
Produces the lexical representation to be used for a `RDF.XSD.Datatype` literal.
By default the lexical representation of a `RDF.XSD.Datatype` is either the
canonical form in case it is created from a non-string Elixir value or, if it
is created from a string, just with that string as the lexical form.
But there can be various reasons for why this should be different for certain
datatypes. For example, for `RDF.XSD.Double`s given as Elixir floats, we want the
default lexical representation to be the decimal and not the canonical
exponential form. Another reason might be that additional options are given
which should be taken into account in the lexical form.
If the lexical representation for a given `value` and `lexical` should be the
canonical one, an implementation should return `nil`.
"""
@callback init_valid_lexical(any, uncanonical_lexical, Keyword.t()) :: uncanonical_lexical
@doc """
Produces the lexical representation of an invalid value.
The default implementation of the `_using__` macro just returns `to_string/1`
The default implementation of the `_using__` macro just returns the `to_string/1`
representation of the value.
"""
@callback init_invalid_lexical(any, Keyword.t()) :: String.t()
@doc """
Returns the `RDF.XSD.Datatype` for a datatype IRI.
"""
defdelegate get(id), to: RDF.Literal.Datatype.Registry, as: :xsd_datatype
@doc false
@ -111,6 +207,9 @@ defmodule RDF.XSD.Datatype do
"""
def __xsd_datatype_indicator__, do: true
@doc """
Checks if the given literal has datatype this or a datatype that is derived of it.
"""
@impl RDF.Literal.Datatype
def datatype?(%RDF.Literal{literal: literal}), do: datatype?(literal)
def datatype?(%datatype{}), do: datatype?(datatype)
@ -129,6 +228,9 @@ defmodule RDF.XSD.Datatype do
def datatype!(value),
do: raise RDF.XSD.Datatype.Mismatch, value: value, expected_type: __MODULE__
@doc """
Creates a new `RDF.Literal` with this datatype and the given `value`.
"""
# Dialyzer causes a warning on all primitives since the facet_conform?/2 call
# always returns true there, so the other branch is unnecessary. This could
# be fixed by generating a special version for primitives, but it's not worth
@ -171,6 +273,9 @@ defmodule RDF.XSD.Datatype do
end
end
@doc """
Creates a new `RDF.Literal` with this datatype and the given `value` or fails when it is not valid.
"""
@impl RDF.Literal.Datatype
def new!(value, opts \\ []) do
literal = new(value, opts)
@ -205,6 +310,10 @@ defmodule RDF.XSD.Datatype do
literal(%__MODULE__{uncanonical_lexical: init_invalid_lexical(lexical, opts)})
end
@doc """
Returns the value of a `RDF.Literal` of this or a derived datatype.
"""
@impl RDF.Literal.Datatype
def value(%RDF.Literal{literal: literal}), do: value(literal)
def value(%__MODULE__{} = literal), do: literal.value
@ -215,6 +324,9 @@ defmodule RDF.XSD.Datatype do
literal.value
end
@doc """
Returns the lexical form of a `RDF.Literal` of this datatype.
"""
@impl RDF.Literal.Datatype
def lexical(lexical)
@ -225,11 +337,17 @@ defmodule RDF.XSD.Datatype do
def lexical(%__MODULE__{uncanonical_lexical: lexical}), do: lexical
@doc """
Returns the canonical lexical form of a `RDF.Literal` of this datatype.
"""
@impl RDF.Literal.Datatype
def canonical_lexical(%RDF.Literal{literal: literal}), do: canonical_lexical(literal)
def canonical_lexical(%__MODULE__{value: value}) when not is_nil(value), do: canonical_mapping(value)
def canonical_lexical(_), do: nil
@doc """
Produces the canonical representation of a `RDF.Literal` of this datatype.
"""
@impl RDF.Literal.Datatype
def canonical(literal)
@ -245,12 +363,18 @@ defmodule RDF.XSD.Datatype do
def canonical(%__MODULE__{} = literal),
do: literal(%__MODULE__{literal | uncanonical_lexical: nil})
@doc """
Determines if the lexical form of a `RDF.Literal` of this datatype is the canonical form.
"""
@impl RDF.Literal.Datatype
def canonical?(literal)
def canonical?(%RDF.Literal{literal: literal}), do: canonical?(literal)
def canonical?(%__MODULE__{uncanonical_lexical: nil}), do: true
def canonical?(%__MODULE__{}), do: false
@doc """
Determines if a `RDF.Literal` of this or a derived datatype has a proper value of its value space.
"""
@impl RDF.Literal.Datatype
def valid?(literal)
def valid?(%RDF.Literal{literal: literal}), do: valid?(literal)
@ -275,6 +399,16 @@ defmodule RDF.XSD.Datatype do
end
end
@doc """
Compares two `RDF.Literal`s.
If the first literal is greater than the second `:gt` is returned, if less than `:lt` is returned.
If both literal are equal `:eq` is returned.
If the literals can not be compared either `nil` is returned, when they generally can be compared
due to their datatype, or `:indeterminate` is returned, when the order of the given values is
not defined on only partially ordered datatypes.
"""
@spec compare(RDF.Literal.t() | any, RDF.Literal.t() | any) :: RDF.Literal.Datatype.comparison_result | :indeterminate | nil
def compare(left, right)
def compare(left, %RDF.Literal{literal: right}), do: compare(left, right)

View file

@ -1,4 +1,19 @@
defmodule RDF.XSD.Datatype.Primitive do
@moduledoc """
Macros for the definition of primitive XSD datatypes.
"""
@doc """
Specifies the applicability of the given XSD `facet` on a primitive datatype.
For a facet with the name `example_facet` this requires a function
def example_facet_conform?(example_facet_value, literal_value, lexical) do
end
to be defined on the primitive datatype.
"""
defmacro def_applicable_facet(facet) do
quote do
@applicable_facets unquote(facet)

View file

@ -1,4 +1,25 @@
defmodule RDF.XSD.Datatype.Restriction do
@moduledoc """
A `__using__` macro for the derivation of restricted XSD datatypes.
### Example
A new custom datatype can be derived by defining a new datatype module and `use` this module,
specifying a `name`, `id` and `base` datatype and restricting it by specifying some of the
applicable facets of the base datatype:
defmodule MyApp.PersonAge do
use RDF.XSD.Datatype.Restriction,
name: "person_age",
id: "http://example.com/person_age",
base: RDF.XSD.NonNegativeInteger
def_facet_constraint RDF.XSD.Facets.MaxInclusive, 150
end
See `RDF.XSD.Facet` on which facets are available on the existing datatypes.
"""
defmacro __using__(opts) do
base = Keyword.fetch!(opts, :base)

View file

@ -4,7 +4,8 @@ defmodule RDF.XSD.Date do
Options:
- `tz` ... it will also overwrite an eventually already present timezone in an input lexical ...
- `tz`: this allows to specify a timezone which is not supported by Elixir's `Date` struct; note,
that it will also overwrite an eventually already present timezone in an input lexical
"""
@type valid_value :: Date.t() | {Date.t(), String.t()}

View file

@ -1,6 +1,11 @@
defmodule RDF.XSD.Time do
@moduledoc """
`RDF.XSD.Datatype` for XSD times.
Options:
- `tz`: this allows to specify a timezone which is not supported by Elixir's `Time` struct; note,
that it will also overwrite an eventually already present timezone in an input lexical
"""
@type valid_value :: Time.t() | {Time.t(), true}

View file

@ -1,4 +1,46 @@
defmodule RDF.XSD.Facet do
@moduledoc """
A behaviour for XSD restriction facets.
Here's a list of all the `RDF.XSD.Facet`s RDF.ex implements out-of-the-box:
| XSD facet | `RDF.XSD.Facet` |
| :-------------- | :------------- |
| length | `RDF.XSD.Facets.Length` |
| minLength | `RDF.XSD.Facets.MinLength` |
| maxLength | `RDF.XSD.Facets.MaxLength` |
| maxInclusive | `RDF.XSD.Facets.MaxInclusive` |
| maxExclusive | `RDF.XSD.Facets.MaxExclusive` |
| minInclusive | `RDF.XSD.Facets.MinInclusive` |
| minExclusive | `RDF.XSD.Facets.MinExclusive` |
| totalDigits | `RDF.XSD.Facets.TotalDigits` |
| fractionDigits | `RDF.XSD.Facets.FractionDigits` |
| explicitTimezone | `RDF.XSD.Facets.ExplicitTimezone` |
| pattern | `RDF.XSD.Facets.Pattern` |
| whiteSpace | |
| enumeration | |
| assertions | |
Every `RDF.XSD.Datatype.Primitive` defines a set of applicable constraining facets which are can
be used on derivations of this primitive or any of its existing derivations:
| Primitive datatype | Applicable facets |
| :----------------- | :---------------- |
|string | `RDF.XSD.Facets.Length`, `RDF.XSD.Facets.MaxLength`, `RDF.XSD.Facets.MinLength`, `RDF.XSD.Facets.Pattern` |
|boolean | `RDF.XSD.Facets.Pattern` |
|float | `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern` |
|double | `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern` |
|decimal | `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern`, `RDF.XSD.Facets.TotalDigits`, `RDF.XSD.Facets.FractionDigits` |
|decimal | `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern`, `RDF.XSD.Facets.TotalDigits` |
|duration | `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern` |
|dateTime | `RDF.XSD.Facets.ExplicitTimezone`, `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern` |
|time | `RDF.XSD.Facets.ExplicitTimezone`, `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern` |
|date | `RDF.XSD.Facets.ExplicitTimezone`, `RDF.XSD.Facets.MaxExclusive`, `RDF.XSD.Facets.MaxInclusive`, `RDF.XSD.Facets.MinExclusive`, `RDF.XSD.Facets.MinInclusive`, `RDF.XSD.Facets.Pattern` |
|anyURI | `RDF.XSD.Facets.Length`, `RDF.XSD.Facets.MaxLength`, `RDF.XSD.Facets.MinLength`, `RDF.XSD.Facets.Pattern` |
<https://www.w3.org/TR/xmlschema11-2/datatypes.html#rf-facets>
"""
@type t :: module
@doc """