Handle derived datatypes on RDF.Literal.Datatype.compare/2 properly
This commit is contained in:
parent
162e82ed47
commit
98adbaf878
13 changed files with 154 additions and 153 deletions
|
@ -130,20 +130,23 @@ defmodule RDF.Literal.Datatype do
|
||||||
@callback do_equal_value_different_datatypes?(literal, literal) :: boolean | nil
|
@callback do_equal_value_different_datatypes?(literal, literal) :: boolean | nil
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Compares two `RDF.Literal`s.
|
Callback for datatype specific `compare/2` comparisons between two `RDF.Literal`s.
|
||||||
|
|
||||||
Returns `:gt` if value of the first literal is greater than the value of the second in
|
This callback is called by auto-generated `compare/2` function on the implementations, which already deals with the basic cases.
|
||||||
terms of their datatype and `:lt` for vice versa. If the two literals are equal `:eq` is returned.
|
So, implementations can assume the passed arguments are valid `RDF.Literal.Datatype` structs and
|
||||||
For datatypes with only partial ordering `:indeterminate` is returned when the
|
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.
|
order of the given literals is not defined.
|
||||||
|
|
||||||
Returns `nil` when the given arguments are not comparable datatypes or if one
|
`nil` should be returned when the given arguments are not comparable datatypes or if one them is invalid.
|
||||||
them is invalid.
|
|
||||||
|
|
||||||
The default implementation of the `_using__` macro of `RDF.XSD.Datatype`s
|
The default implementation of the `_using__` macro of `RDF.Literal.Datatype`s
|
||||||
compares the values of the `canonical/1` forms of the given literals of this datatype.
|
just compares the values of the given literals.
|
||||||
"""
|
"""
|
||||||
@callback compare(Literal.t() | literal, Literal.t() | literal) :: comparison_result | :indeterminate | nil
|
@callback do_compare(literal, literal) :: comparison_result | :indeterminate | nil
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Updates the value of a `RDF.Literal` without changing everything else.
|
Updates the value of a `RDF.Literal` without changing everything else.
|
||||||
|
@ -348,7 +351,37 @@ defmodule RDF.Literal.Datatype do
|
||||||
defp resource?(%RDF.BlankNode{}), do: true
|
defp resource?(%RDF.BlankNode{}), do: true
|
||||||
defp resource?(_), do: false
|
defp resource?(_), do: false
|
||||||
|
|
||||||
@impl unquote(__MODULE__)
|
# 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
|
||||||
|
def compare(left, right)
|
||||||
|
def compare(left, %RDF.Literal{literal: right}), do: compare(left, right)
|
||||||
|
def compare(%RDF.Literal{literal: left}, right), do: compare(left, right)
|
||||||
|
|
||||||
|
def compare(left, right) do
|
||||||
|
if Literal.datatype?(left) and Literal.datatype?(right) and
|
||||||
|
Literal.Datatype.valid?(left) and Literal.Datatype.valid?(right) do
|
||||||
|
do_compare(left, right)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl RDF.Literal.Datatype
|
||||||
|
def do_compare(%datatype{} = left, %datatype{} = right) do
|
||||||
|
case {datatype.value(left), datatype.value(right)} do
|
||||||
|
{left_value, right_value} when left_value < right_value -> :lt
|
||||||
|
{left_value, right_value} when left_value > right_value -> :gt
|
||||||
|
_ ->
|
||||||
|
if datatype.equal_value?(left, right), do: :eq
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def do_compare(_, _), do: nil
|
||||||
|
|
||||||
|
defoverridable compare: 2,
|
||||||
|
do_compare: 2
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl unquote(__MODULE__)
|
||||||
def update(literal, fun, opts \\ [])
|
def update(literal, fun, opts \\ [])
|
||||||
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
|
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
|
||||||
def update(%__MODULE__{} = literal, fun, opts) do
|
def update(%__MODULE__{} = literal, fun, opts) do
|
||||||
|
|
|
@ -92,21 +92,17 @@ defmodule RDF.Literal.Generic do
|
||||||
def do_equal_value_same_or_derived_datatypes?(_, _), do: nil
|
def do_equal_value_same_or_derived_datatypes?(_, _), do: nil
|
||||||
|
|
||||||
@impl Datatype
|
@impl Datatype
|
||||||
def compare(left, %Literal{literal: right}), do: compare(left, right)
|
def do_compare(%__MODULE__{datatype: datatype} = left_literal,
|
||||||
def compare(%Literal{literal: left}, right), do: compare(left, right)
|
%__MODULE__{datatype: datatype} = right_literal) do
|
||||||
def compare(%__MODULE__{datatype: datatype} = literal1,
|
case {left_literal.value, right_literal.value} do
|
||||||
%__MODULE__{datatype: datatype} = literal2) do
|
{left_value, right_value} when left_value < right_value -> :lt
|
||||||
if valid?(literal1) and valid?(literal2) do
|
{left_value, right_value} when left_value > right_value -> :gt
|
||||||
case {literal1.value, literal2.value} do
|
_ ->
|
||||||
{value1, value2} when value1 < value2 -> :lt
|
if equal_value?(left_literal, right_literal), do: :eq
|
||||||
{value1, value2} when value1 > value2 -> :gt
|
|
||||||
_ ->
|
|
||||||
if equal_value?(literal1, literal2), do: :eq
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare(_, _), do: nil
|
def do_compare(_, _), do: nil
|
||||||
|
|
||||||
@impl Datatype
|
@impl Datatype
|
||||||
def update(literal, fun, opts \\ [])
|
def update(literal, fun, opts \\ [])
|
||||||
|
|
|
@ -78,23 +78,6 @@ defmodule RDF.LangString do
|
||||||
@impl Datatype
|
@impl Datatype
|
||||||
def do_cast(_), do: nil
|
def do_cast(_), do: nil
|
||||||
|
|
||||||
@impl Datatype
|
|
||||||
def compare(left, %Literal{literal: right}), do: compare(left, right)
|
|
||||||
def compare(%Literal{literal: left}, right), do: compare(left, right)
|
|
||||||
def compare(%__MODULE__{language: language_tag} = literal1,
|
|
||||||
%__MODULE__{language: language_tag} = literal2) do
|
|
||||||
if valid?(literal1) and valid?(literal2) do
|
|
||||||
case {canonical(literal1).literal.value, canonical(literal2).literal.value} do
|
|
||||||
{value1, value2} when value1 < value2 -> :lt
|
|
||||||
{value1, value2} when value1 > value2 -> :gt
|
|
||||||
_ ->
|
|
||||||
if equal_value?(literal1, literal2), do: :eq
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def compare(_, _), do: nil
|
|
||||||
|
|
||||||
@impl Datatype
|
@impl Datatype
|
||||||
def update(literal, fun, opts \\ [])
|
def update(literal, fun, opts \\ [])
|
||||||
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
|
def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts)
|
||||||
|
|
|
@ -13,8 +13,6 @@ defmodule RDF.XSD.Datatype do
|
||||||
:uncanonical_lexical => uncanonical_lexical()
|
:uncanonical_lexical => uncanonical_lexical()
|
||||||
}
|
}
|
||||||
|
|
||||||
@type comparison_result :: :lt | :gt | :eq
|
|
||||||
|
|
||||||
import RDF.Utils.Guards
|
import RDF.Utils.Guards
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -272,6 +270,17 @@ defmodule RDF.XSD.Datatype do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def compare(left, right)
|
||||||
|
def compare(left, %RDF.Literal{literal: right}), do: compare(left, right)
|
||||||
|
def compare(%RDF.Literal{literal: left}, right), do: compare(left, right)
|
||||||
|
|
||||||
|
def compare(left, right) do
|
||||||
|
if RDF.XSD.datatype?(left) and RDF.XSD.datatype?(right) and
|
||||||
|
RDF.Literal.Datatype.valid?(left) and RDF.Literal.Datatype.valid?(right) do
|
||||||
|
do_compare(left, right)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
defimpl Inspect do
|
defimpl Inspect do
|
||||||
"Elixir.Inspect." <> datatype_name = to_string(__MODULE__)
|
"Elixir.Inspect." <> datatype_name = to_string(__MODULE__)
|
||||||
@datatype_name datatype_name
|
@datatype_name datatype_name
|
||||||
|
|
|
@ -56,24 +56,19 @@ defmodule RDF.XSD.Datatype.Primitive do
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def do_equal_value_different_datatypes?(left, right), do: nil
|
def do_equal_value_different_datatypes?(left, right), do: nil
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def compare(left, right)
|
def do_compare(%left_datatype{} = left, %right_datatype{} = right) do
|
||||||
def compare(left, %RDF.Literal{literal: right}), do: compare(left, right)
|
if left_datatype.datatype?(right_datatype) or right_datatype.datatype?(left_datatype) do
|
||||||
def compare(%RDF.Literal{literal: left}, right), do: compare(left, right)
|
case {left_datatype.value(left), right_datatype.value(right)} do
|
||||||
|
{left_value, right_value} when left_value < right_value -> :lt
|
||||||
def compare(
|
{left_value, right_value} when left_value > right_value -> :gt
|
||||||
%__MODULE__{value: left_value} = left,
|
_ ->
|
||||||
%__MODULE__{value: right_value} = right
|
if left_datatype.equal_value?(left, right), do: :eq
|
||||||
)
|
end
|
||||||
when not (is_nil(left_value) or is_nil(right_value)) do
|
|
||||||
case {left |> canonical() |> value(), right |> canonical() |> value()} do
|
|
||||||
{value1, value2} when value1 < value2 -> :lt
|
|
||||||
{value1, value2} when value1 > value2 -> :gt
|
|
||||||
_ -> if equal_value?(left, right), do: :eq
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare(_, _), do: nil
|
def do_compare(_, _), do: nil
|
||||||
|
|
||||||
defoverridable canonical_mapping: 1,
|
defoverridable canonical_mapping: 1,
|
||||||
do_cast: 1,
|
do_cast: 1,
|
||||||
|
@ -81,7 +76,7 @@ defmodule RDF.XSD.Datatype.Primitive do
|
||||||
init_invalid_lexical: 2,
|
init_invalid_lexical: 2,
|
||||||
do_equal_value_same_or_derived_datatypes?: 2,
|
do_equal_value_same_or_derived_datatypes?: 2,
|
||||||
do_equal_value_different_datatypes?: 2,
|
do_equal_value_different_datatypes?: 2,
|
||||||
compare: 2
|
do_compare: 2
|
||||||
|
|
||||||
@before_compile unquote(__MODULE__)
|
@before_compile unquote(__MODULE__)
|
||||||
end
|
end
|
||||||
|
|
|
@ -86,14 +86,14 @@ defmodule RDF.XSD.Datatype.Restriction do
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def compare(left, right), do: @base.compare(left, right)
|
def do_compare(left, right), do: @base.do_compare(left, right)
|
||||||
|
|
||||||
defoverridable canonical_mapping: 1,
|
defoverridable canonical_mapping: 1,
|
||||||
do_cast: 1,
|
do_cast: 1,
|
||||||
equal_value?: 2,
|
equal_value?: 2,
|
||||||
do_equal_value_same_or_derived_datatypes?: 2,
|
do_equal_value_same_or_derived_datatypes?: 2,
|
||||||
do_equal_value_different_datatypes?: 2,
|
do_equal_value_different_datatypes?: 2,
|
||||||
compare: 2
|
do_compare: 2
|
||||||
|
|
||||||
Module.register_attribute(__MODULE__, :facets, accumulate: true)
|
Module.register_attribute(__MODULE__, :facets, accumulate: true)
|
||||||
|
|
||||||
|
|
|
@ -183,21 +183,7 @@ defmodule RDF.XSD.Date do
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def compare(left, right)
|
def do_compare(%{value: value1}, %{value: value2}) do
|
||||||
def compare(left, %RDF.Literal{literal: right}), do: compare(left, right)
|
|
||||||
def compare(%RDF.Literal{literal: left}, right), do: compare(left, right)
|
|
||||||
|
|
||||||
def compare(
|
|
||||||
%__MODULE__{value: value1},
|
|
||||||
%__MODULE__{value: value2}
|
|
||||||
)
|
|
||||||
when is_nil(value1) or is_nil(value2),
|
|
||||||
do: nil
|
|
||||||
|
|
||||||
def compare(
|
|
||||||
%__MODULE__{value: value1},
|
|
||||||
%__MODULE__{value: value2}
|
|
||||||
) do
|
|
||||||
XSD.DateTime.compare(
|
XSD.DateTime.compare(
|
||||||
comparison_normalization(value1),
|
comparison_normalization(value1),
|
||||||
comparison_normalization(value2)
|
comparison_normalization(value2)
|
||||||
|
@ -209,27 +195,27 @@ defmodule RDF.XSD.Date do
|
||||||
# ordering comparisons in the date-3 test. The following implementation would allow
|
# ordering comparisons in the date-3 test. The following implementation would allow
|
||||||
# an ordering comparisons between date and datetimes.
|
# an ordering comparisons between date and datetimes.
|
||||||
#
|
#
|
||||||
# def compare(
|
# def do_compare(
|
||||||
# %__MODULE__{value: date_value},
|
# %__MODULE__{value: date_value},
|
||||||
# %XSD.DateTime{} = datetime_literal
|
# %XSD.DateTime{} = datetime_literal
|
||||||
# ) do
|
# ) do
|
||||||
# XSD.DateTime.compare(
|
# XSD.DateTime.compare(
|
||||||
# comparison_normalization(date_value),
|
# comparison_normalization(date_value).literal,
|
||||||
# datetime_literal
|
# datetime_literal
|
||||||
# )
|
# )
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# def compare(
|
# def do_compare(
|
||||||
# %XSD.DateTime{} = datetime_literal,
|
# %XSD.DateTime{} = datetime_literal,
|
||||||
# %__MODULE__{value: date_value}
|
# %__MODULE__{value: date_value}
|
||||||
# ) do
|
# ) do
|
||||||
# XSD.DateTime.compare(
|
# XSD.DateTime.do_compare(
|
||||||
# datetime_literal,
|
# datetime_literal,
|
||||||
# comparison_normalization(date_value)
|
# comparison_normalization(date_value).literal
|
||||||
# )
|
# )
|
||||||
# end
|
# end
|
||||||
|
|
||||||
def compare(_, _), do: nil
|
def do_compare(_, _), do: nil
|
||||||
|
|
||||||
defp comparison_normalization({date, tz}) do
|
defp comparison_normalization({date, tz}) do
|
||||||
(Date.to_iso8601(date) <> "T00:00:00" <> tz)
|
(Date.to_iso8601(date) <> "T00:00:00" <> tz)
|
||||||
|
|
|
@ -185,15 +185,10 @@ defmodule RDF.XSD.DateTime do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def compare(left, right)
|
def do_compare(left, right)
|
||||||
def compare(left, %RDF.Literal{literal: right}), do: compare(left, right)
|
|
||||||
def compare(%RDF.Literal{literal: left}, right), do: compare(left, right)
|
|
||||||
|
|
||||||
def compare(
|
def do_compare(%{value: %type{} = value1}, %{value: %type{} = value2}) do
|
||||||
%__MODULE__{value: %type{} = value1},
|
|
||||||
%__MODULE__{value: %type{} = value2}
|
|
||||||
) do
|
|
||||||
type.compare(value1, value2)
|
type.compare(value1, value2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -202,37 +197,31 @@ defmodule RDF.XSD.DateTime do
|
||||||
# ordering comparisons in the date-3 test. The following implementation would allow
|
# ordering comparisons in the date-3 test. The following implementation would allow
|
||||||
# an ordering comparisons between date and datetimes.
|
# an ordering comparisons between date and datetimes.
|
||||||
#
|
#
|
||||||
# def compare(%__MODULE__{} = literal1, %XSD.Date{} = literal2) do
|
# def do_compare(%__MODULE__{} = literal1, %XSD.Date{} = literal2) do
|
||||||
# XSD.Date.compare(literal1, literal2)
|
# XSD.Date.do_compare(literal1, literal2)
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# def compare(%XSD.Date{} = literal1, %__MODULE__{} = literal2) do
|
# def do_compare(%XSD.Date{} = literal1, %__MODULE__{} = literal2) do
|
||||||
# XSD.Date.compare(literal1, literal2)
|
# XSD.Date.do_compare(literal1, literal2)
|
||||||
# end
|
# end
|
||||||
|
|
||||||
def compare(
|
def do_compare(%{value: %DateTime{}} = left, %{value: %NaiveDateTime{} = right_value}) do
|
||||||
%__MODULE__{value: %DateTime{}} = left,
|
|
||||||
%__MODULE__{value: %NaiveDateTime{} = right_value}
|
|
||||||
) do
|
|
||||||
cond do
|
cond do
|
||||||
compare(left, new(to_datetime(right_value, "+"))) == :lt -> :lt
|
do_compare(left, new(to_datetime(right_value, "+")).literal) == :lt -> :lt
|
||||||
compare(left, new(to_datetime(right_value, "-"))) == :gt -> :gt
|
do_compare(left, new(to_datetime(right_value, "-")).literal) == :gt -> :gt
|
||||||
true -> :indeterminate
|
true -> :indeterminate
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare(
|
def do_compare(%{value: %NaiveDateTime{} = left}, %{value: %DateTime{}} = right_literal) do
|
||||||
%__MODULE__{value: %NaiveDateTime{} = left},
|
|
||||||
%__MODULE__{value: %DateTime{}} = right_literal
|
|
||||||
) do
|
|
||||||
cond do
|
cond do
|
||||||
compare(new(to_datetime(left, "-")), right_literal) == :lt -> :lt
|
do_compare(new(to_datetime(left, "-")).literal, right_literal) == :lt -> :lt
|
||||||
compare(new(to_datetime(left, "+")), right_literal) == :gt -> :gt
|
do_compare(new(to_datetime(left, "+")).literal, right_literal) == :gt -> :gt
|
||||||
true -> :indeterminate
|
true -> :indeterminate
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare(_, _), do: nil
|
def do_compare(_, _), do: nil
|
||||||
|
|
||||||
defp to_datetime(naive_datetime, offset) do
|
defp to_datetime(naive_datetime, offset) do
|
||||||
(NaiveDateTime.to_iso8601(naive_datetime) <> offset <> "14:00")
|
(NaiveDateTime.to_iso8601(naive_datetime) <> offset <> "14:00")
|
||||||
|
|
|
@ -153,14 +153,14 @@ defmodule RDF.XSD.Decimal do
|
||||||
|
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.equal_value?(left, right)
|
def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right)
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.equal_value?(left, right)
|
def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right)
|
||||||
|
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def compare(left, right), do: XSD.Numeric.compare(left, right)
|
def do_compare(left, right), do: XSD.Numeric.do_compare(left, right)
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
The number of digits in the XML Schema canonical form of the literal value.
|
The number of digits in the XML Schema canonical form of the literal value.
|
||||||
|
|
|
@ -161,12 +161,12 @@ defmodule RDF.XSD.Double do
|
||||||
|
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.equal_value?(left, right)
|
def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right)
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.equal_value?(left, right)
|
def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right)
|
||||||
|
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def compare(left, right), do: XSD.Numeric.compare(left, right)
|
def do_compare(left, right), do: XSD.Numeric.do_compare(left, right)
|
||||||
end
|
end
|
||||||
|
|
|
@ -100,13 +100,13 @@ defmodule RDF.XSD.Integer do
|
||||||
end
|
end
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.equal_value?(left, right)
|
def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right)
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.equal_value?(left, right)
|
def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right)
|
||||||
|
|
||||||
@impl RDF.Literal.Datatype
|
@impl RDF.Literal.Datatype
|
||||||
def compare(left, right), do: XSD.Numeric.compare(left, right)
|
def do_compare(left, right), do: XSD.Numeric.do_compare(left, right)
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
The number of digits in the XML Schema canonical form of the literal value.
|
The number of digits in the XML Schema canonical form of the literal value.
|
||||||
|
|
|
@ -20,10 +20,10 @@ defmodule RDF.XSD.Numeric do
|
||||||
- <https://www.w3.org/TR/sparql11-query/#OperatorMapping>
|
- <https://www.w3.org/TR/sparql11-query/#OperatorMapping>
|
||||||
- <https://www.w3.org/TR/xpath-functions/#func-numeric-equal>
|
- <https://www.w3.org/TR/xpath-functions/#func-numeric-equal>
|
||||||
"""
|
"""
|
||||||
@spec equal_value?(t() | any, t() | any) :: boolean
|
@spec do_equal_value?(t() | any, t() | any) :: boolean
|
||||||
def equal_value?(left, right)
|
def do_equal_value?(left, right)
|
||||||
|
|
||||||
def equal_value?(%left_datatype{value: left}, %right_datatype{value: right}) do
|
def do_equal_value?(%left_datatype{value: left}, %right_datatype{value: right}) do
|
||||||
cond do
|
cond do
|
||||||
XSD.Decimal.datatype?(left_datatype) or XSD.Decimal.datatype?(right_datatype) ->
|
XSD.Decimal.datatype?(left_datatype) or XSD.Decimal.datatype?(right_datatype) ->
|
||||||
equal_decimal_value?(left, right)
|
equal_decimal_value?(left, right)
|
||||||
|
@ -36,7 +36,7 @@ defmodule RDF.XSD.Numeric do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def equal_value?(_, _), do: nil
|
def do_equal_value?(_, _), do: nil
|
||||||
|
|
||||||
defp equal_decimal_value?(%D{} = left, %D{} = right), do: D.equal?(left, right)
|
defp equal_decimal_value?(%D{} = left, %D{} = right), do: D.equal?(left, right)
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ defmodule RDF.XSD.Numeric do
|
||||||
defp new_decimal(value) when is_float(value), do: D.from_float(value)
|
defp new_decimal(value) when is_float(value), do: D.from_float(value)
|
||||||
defp new_decimal(value), do: D.new(value)
|
defp new_decimal(value), do: D.new(value)
|
||||||
|
|
||||||
@doc """
|
@doc !"""
|
||||||
Compares two numeric XSD literals.
|
Compares two numeric XSD literals.
|
||||||
|
|
||||||
Returns `:gt` if first literal is greater than the second and `:lt` for vice
|
Returns `:gt` if first literal is greater than the second and `:lt` for vice
|
||||||
|
@ -60,36 +60,14 @@ defmodule RDF.XSD.Numeric do
|
||||||
Returns `nil` when the given arguments are not comparable datatypes.
|
Returns `nil` when the given arguments are not comparable datatypes.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
@spec compare(Literal.t | t, Literal.t | t) :: XSD.Datatype.comparison_result() | nil
|
@spec do_compare(t, t) :: Literal.Datatype.comparison_result() | nil
|
||||||
def compare(left, right)
|
def do_compare(left, right)
|
||||||
def compare(left, %Literal{literal: right}), do: compare(left, right)
|
|
||||||
def compare(%Literal{literal: left}, right), do: compare(left, right)
|
|
||||||
|
|
||||||
def compare(
|
def do_compare(%left_datatype{value: left}, %right_datatype{value: right}) do
|
||||||
%XSD.Decimal{value: left},
|
|
||||||
%right_datatype{value: right}
|
|
||||||
) do
|
|
||||||
if datatype?(right_datatype) do
|
|
||||||
compare_decimal_value(left, right)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def compare(
|
|
||||||
%left_datatype{value: left},
|
|
||||||
%XSD.Decimal{value: right}
|
|
||||||
) do
|
|
||||||
if datatype?(left_datatype) do
|
|
||||||
compare_decimal_value(left, right)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def compare(
|
|
||||||
%left_datatype{value: left},
|
|
||||||
%right_datatype{value: right}
|
|
||||||
)
|
|
||||||
when not (is_nil(left) or is_nil(right)) do
|
|
||||||
if datatype?(left_datatype) and datatype?(right_datatype) do
|
if datatype?(left_datatype) and datatype?(right_datatype) do
|
||||||
cond do
|
cond do
|
||||||
|
XSD.Decimal.datatype?(left_datatype) or XSD.Decimal.datatype?(right_datatype) ->
|
||||||
|
compare_decimal_value(left, right)
|
||||||
left < right -> :lt
|
left < right -> :lt
|
||||||
left > right -> :gt
|
left > right -> :gt
|
||||||
true -> :eq
|
true -> :eq
|
||||||
|
@ -97,7 +75,7 @@ defmodule RDF.XSD.Numeric do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def compare(_, _), do: nil
|
def do_compare(_, _), do: nil
|
||||||
|
|
||||||
defp compare_decimal_value(%D{} = left, %D{} = right), do: D.cmp(left, right)
|
defp compare_decimal_value(%D{} = left, %D{} = right), do: D.cmp(left, right)
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
use ExUnit.Case
|
use ExUnit.Case
|
||||||
|
|
||||||
alias RDF.XSD
|
alias RDF.XSD
|
||||||
|
alias RDF.TestDatatypes.{Initials, Age, DecimalUnitInterval, CustomTime, DateWithoutTz, DateTimeWithTz}
|
||||||
|
|
||||||
describe "XSD.String" do
|
describe "XSD.String" do
|
||||||
@ordered_strings [
|
@ordered_strings [
|
||||||
|
@ -17,6 +18,13 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
assert_equal({XSD.string("foo"), XSD.string("foo")})
|
assert_equal({XSD.string("foo"), XSD.string("foo")})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "valid comparisons between derived string literals" do
|
||||||
|
assert_equal({Initials.new("fo"), XSD.string("fo")})
|
||||||
|
assert_order({Initials.new("ba"), Initials.new("fo")})
|
||||||
|
assert_order({Initials.new("ba"), XSD.string("foo")})
|
||||||
|
assert_order({XSD.string("bar"), Initials.new("fo")})
|
||||||
|
end
|
||||||
|
|
||||||
test "invalid comparison between string and langString literals" do
|
test "invalid comparison between string and langString literals" do
|
||||||
assert_incomparable({XSD.string("foo"), RDF.langString("foo", :en)})
|
assert_incomparable({XSD.string("foo"), RDF.langString("foo", :en)})
|
||||||
end
|
end
|
||||||
|
@ -50,7 +58,14 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
{XSD.non_negative_integer(0), XSD.integer(1)},
|
{XSD.non_negative_integer(0), XSD.integer(1)},
|
||||||
{XSD.integer(0), XSD.positive_integer(1)},
|
{XSD.integer(0), XSD.positive_integer(1)},
|
||||||
{XSD.non_negative_integer(0), XSD.positive_integer(1)},
|
{XSD.non_negative_integer(0), XSD.positive_integer(1)},
|
||||||
{XSD.positive_integer(1), XSD.non_negative_integer(2)}
|
{XSD.positive_integer(1), XSD.non_negative_integer(2)},
|
||||||
|
{XSD.positive_integer(1), XSD.non_negative_integer(2)},
|
||||||
|
{Age.new(1), Age.new(2)},
|
||||||
|
{Age.new(1), XSD.integer(2)},
|
||||||
|
{XSD.non_negative_integer(1), Age.new(2)},
|
||||||
|
{Age.new(1), XSD.decimal(2.1)},
|
||||||
|
{XSD.decimal(0.1), DecimalUnitInterval.new(0.2)},
|
||||||
|
{DecimalUnitInterval.new(0.3), Age.new(2)},
|
||||||
],
|
],
|
||||||
&assert_order/1
|
&assert_order/1
|
||||||
)
|
)
|
||||||
|
@ -89,6 +104,7 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
)
|
)
|
||||||
|
|
||||||
assert_order({XSD.datetime("2000-01-15T12:00:00"), XSD.datetime("2000-01-16T12:00:00Z")})
|
assert_order({XSD.datetime("2000-01-15T12:00:00"), XSD.datetime("2000-01-16T12:00:00Z")})
|
||||||
|
assert_order({XSD.datetime("2000-01-15T12:00:00"), DateTimeWithTz.new("2000-01-16T12:00:00Z")})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "when unequal due to missing time zone" do
|
test "when unequal due to missing time zone" do
|
||||||
|
@ -110,6 +126,10 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
{XSD.datetime("2002-04-02T23:00:00-04:00"), XSD.datetime("2002-04-03T02:00:00-01:00")}
|
{XSD.datetime("2002-04-02T23:00:00-04:00"), XSD.datetime("2002-04-03T02:00:00-01:00")}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert_equal(
|
||||||
|
{DateTimeWithTz.new("2002-04-02T23:00:00-04:00"), XSD.datetime("2002-04-03T02:00:00-01:00")}
|
||||||
|
)
|
||||||
|
|
||||||
assert_equal({XSD.datetime("1999-12-31T24:00:00"), XSD.datetime("2000-01-01T00:00:00")})
|
assert_equal({XSD.datetime("1999-12-31T24:00:00"), XSD.datetime("2000-01-01T00:00:00")})
|
||||||
# TODO: Assume that the dynamic context provides an implicit timezone value of -05:00
|
# TODO: Assume that the dynamic context provides an implicit timezone value of -05:00
|
||||||
# assert_equal {XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T23:00:00+06:00")}
|
# assert_equal {XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T23:00:00+06:00")}
|
||||||
|
@ -127,6 +147,10 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
assert_indeterminate(
|
assert_indeterminate(
|
||||||
{XSD.datetime("2000-01-16T00:00:00"), XSD.datetime("2000-01-16T12:00:00Z")}
|
{XSD.datetime("2000-01-16T00:00:00"), XSD.datetime("2000-01-16T12:00:00Z")}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert_indeterminate(
|
||||||
|
{XSD.datetime("2000-01-16T00:00:00"), DateTimeWithTz.new("2000-01-16T12:00:00Z")}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -135,6 +159,8 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
assert_order({XSD.date("2002-04-02"), XSD.date("2002-04-03")})
|
assert_order({XSD.date("2002-04-02"), XSD.date("2002-04-03")})
|
||||||
assert_order({XSD.date("2002-04-02+01:00"), XSD.date("2002-04-03+00:00")})
|
assert_order({XSD.date("2002-04-02+01:00"), XSD.date("2002-04-03+00:00")})
|
||||||
assert_order({XSD.date("2002-04-02"), XSD.date("2002-04-03Z")})
|
assert_order({XSD.date("2002-04-02"), XSD.date("2002-04-03Z")})
|
||||||
|
assert_order({DateWithoutTz.new("2002-04-02"), XSD.date("2002-04-03Z")})
|
||||||
|
assert_order({DateWithoutTz.new("2002-04-02"), DateWithoutTz.new("2002-04-03")})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "when equal" do
|
test "when equal" do
|
||||||
|
@ -143,12 +169,14 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
assert_equal({XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02+00:00")})
|
assert_equal({XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02+00:00")})
|
||||||
assert_equal({XSD.date("2002-04-02Z"), XSD.date("2002-04-02+00:00")})
|
assert_equal({XSD.date("2002-04-02Z"), XSD.date("2002-04-02+00:00")})
|
||||||
assert_equal({XSD.date("2002-04-02Z"), XSD.date("2002-04-02-00:00")})
|
assert_equal({XSD.date("2002-04-02Z"), XSD.date("2002-04-02-00:00")})
|
||||||
|
assert_equal({XSD.date("2002-04-02"), DateWithoutTz.new("2002-04-02")})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "when indeterminate" do
|
test "when indeterminate" do
|
||||||
assert_indeterminate({XSD.date("2002-04-02Z"), XSD.date("2002-04-02")})
|
assert_indeterminate({XSD.date("2002-04-02Z"), XSD.date("2002-04-02")})
|
||||||
assert_indeterminate({XSD.date("2002-04-02+00:00"), XSD.date("2002-04-02")})
|
assert_indeterminate({XSD.date("2002-04-02+00:00"), XSD.date("2002-04-02")})
|
||||||
assert_indeterminate({XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02")})
|
assert_indeterminate({XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02")})
|
||||||
|
assert_indeterminate({XSD.date("2002-04-02Z"), DateWithoutTz.new("2002-04-02")})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -187,18 +215,21 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
test "when unequal" do
|
test "when unequal" do
|
||||||
assert_order({XSD.time("12:00:00+01:00"), XSD.time("13:00:00+01:00")})
|
assert_order({XSD.time("12:00:00+01:00"), XSD.time("13:00:00+01:00")})
|
||||||
assert_order({XSD.time("12:00:00"), XSD.time("13:00:00")})
|
assert_order({XSD.time("12:00:00"), XSD.time("13:00:00")})
|
||||||
|
assert_order({CustomTime.new("12:00:00"), CustomTime.new("13:00:00")})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "when equal" do
|
test "when equal" do
|
||||||
assert_equal({XSD.time("12:00:00+01:00"), XSD.time("12:00:00+01:00")})
|
assert_equal({XSD.time("12:00:00+01:00"), XSD.time("12:00:00+01:00")})
|
||||||
assert_equal({XSD.time("12:00:00"), XSD.time("12:00:00")})
|
assert_equal({XSD.time("12:00:00"), XSD.time("12:00:00")})
|
||||||
|
assert_equal({CustomTime.new("12:00:00+01:00"), XSD.time("12:00:00+01:00")})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "when indeterminate" do
|
# TODO:
|
||||||
assert_indeterminate({XSD.date("2002-04-02Z"), XSD.date("2002-04-02")})
|
# test "when indeterminate" do
|
||||||
assert_indeterminate({XSD.date("2002-04-02+00:00"), XSD.date("2002-04-02")})
|
# assert_indeterminate({XSD.time("12:00:00Z"), XSD.time("12:00:00")})
|
||||||
assert_indeterminate({XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02")})
|
# assert_indeterminate({XSD.time("12:00:00+00:00"), XSD.time("12:00:00")})
|
||||||
end
|
# assert_indeterminate({XSD.time("12:00:00-00:00"), XSD.time("12:00:00")})
|
||||||
|
# end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "incomparable" do
|
describe "incomparable" do
|
||||||
|
@ -231,6 +262,7 @@ defmodule RDF.XSD.ComparisonTest do
|
||||||
Enum.each(
|
Enum.each(
|
||||||
[
|
[
|
||||||
{XSD.true(), XSD.boolean(42)},
|
{XSD.true(), XSD.boolean(42)},
|
||||||
|
{XSD.false(), Age.new(242)},
|
||||||
{XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002.04.02 12:00")},
|
{XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002.04.02 12:00")},
|
||||||
{XSD.date("2002-04-02"), XSD.date("2002.04.02")},
|
{XSD.date("2002-04-02"), XSD.date("2002.04.02")},
|
||||||
{XSD.time("12:00:00"), XSD.time("12-00-00")}
|
{XSD.time("12:00:00"), XSD.time("12-00-00")}
|
||||||
|
|
Loading…
Reference in a new issue