Add comparable?/2 functions to RDF.Literal and RDF.Literal.Datatypes

This commit is contained in:
Marcel Otto 2020-04-18 00:31:03 +02:00
parent 66cc9292c9
commit 287839740c
8 changed files with 79 additions and 0 deletions

View file

@ -202,6 +202,13 @@ defmodule RDF.Literal do
def equal_value?(_, _), do: false
@spec comparable?(t, t) :: boolean
def comparable?(%__MODULE__{literal: %datatype{} = left}, right) do
Datatype.Registry.rdf_datatype(datatype).comparable?(left, right)
end
def comparable?(_, _), do: false
@spec compare(t, t) :: Datatype.comparison_result | :indeterminate | nil
def compare(%__MODULE__{literal: %datatype{} = left}, right) do
Datatype.Registry.rdf_datatype(datatype).compare(left, right)

View file

@ -86,6 +86,15 @@ defmodule RDF.Literal.Datatype do
"""
@callback compare(Literal.t() | literal, Literal.t() | literal) :: comparison_result | :indeterminate | nil
@doc """
Checks if two datatype literals are comparable.
This basically mimics the comparability check in terms of the `=` operator of the SPARQL
which handles equality comparisons between some datatypes as errors, i.e. considering
them as incompatible.
"""
@callback comparable?(Literal.t() | literal, Literal.t() | literal) :: boolean
@callback update(Literal.t() | literal, fun()) :: Literal.t
@callback update(Literal.t() | literal, fun(), keyword) :: Literal.t
end

View file

@ -89,6 +89,14 @@ defmodule RDF.Literal.Generic do
def equal_value?(%Literal{literal: left}, right), do: equal_value?(left, right)
def equal_value?(%__MODULE__{} = left, right), do: left == right
@impl Datatype
def comparable?(left, %Literal{literal: right}), do: comparable?(left, right)
def comparable?(%Literal{literal: left}, right), do: comparable?(left, right)
def comparable?(%__MODULE__{datatype: left_datatype},
%__MODULE__{datatype: right_datatype}),
do: left_datatype == right_datatype
def comparable?(_, _), do: false
@impl Datatype
def compare(left, %Literal{literal: right}), do: compare(left, right)
def compare(%Literal{literal: left}, right), do: compare(left, right)

View file

@ -95,6 +95,12 @@ defmodule RDF.LangString do
def equal_value?(%__MODULE__{} = left, right), do: left == right
def equal_value?(_, _), do: false
@impl Datatype
def comparable?(left, %Literal{literal: right}), do: comparable?(left, right)
def comparable?(%Literal{literal: left}, right), do: comparable?(left, right)
def comparable?(%__MODULE__{}, %__MODULE__{}), do: true
def comparable?(_, _), do: false
@impl Datatype
def compare(left, %Literal{literal: right}), do: compare(left, right)
def compare(%Literal{literal: left}, right), do: compare(left, right)

View file

@ -92,6 +92,14 @@ defmodule RDF.Literal.XSD do
end
def equal_value?(_, _), do: false
@impl RDF.Literal.Datatype
def comparable?(left, %Literal{literal: right}), do: comparable?(left, right)
def comparable?(%Literal{literal: left}, right), do: comparable?(left, right)
def comparable?(%unquote(xsd_datatype){} = left, right) do
XSD.Literal.comparable?(left, right)
end
def comparable?(_, _), do: false
@impl RDF.Literal.Datatype
@dialyzer {:nowarn_function, compare: 2} # TODO: Why is this warning raised
def compare(left, %Literal{literal: right}), do: compare(left, right)

View file

@ -165,6 +165,22 @@ defmodule RDF.Literal.GenericTest do
assert Generic.equal_value?(Generic.new("foo", datatype: "foo"), RDF.XSD.String.new("foo")) == false
end
test "comparable?/2" do
Enum.each @valid, fn {input, {_, datatype}} ->
assert Generic.comparable?(
Generic.new(input, datatype: datatype),
Generic.new(input, datatype: datatype)) == true
end
assert Generic.comparable?(
Generic.new("foo", datatype: "http://example.com/foo"),
Generic.new("foo", datatype: "http://example.com/bar")) == false
assert Generic.comparable?(
Generic.new("foo", datatype: "http://example.com/foo"),
RDF.string("foo")) == false
end
test "compare/2" do
Enum.each @valid, fn {input, {_, datatype}} ->
assert Generic.compare(

View file

@ -198,6 +198,22 @@ defmodule RDF.LangStringTest do
assert LangString.equal_value?(RDF.XSD.String.new("foo"), LangString.new("foo", [])) == false
end
test "comparable?/2" do
Enum.each @valid, fn {input, {_, language}} ->
assert LangString.comparable?(
LangString.new(input, language: language),
LangString.new(input, language: language)) == true
end
assert LangString.comparable?(
LangString.new("foo", language: "en"),
LangString.new("foo", language: "de")) == true # TODO: This is an assumption. Couldn't find anything in the specs yet.
assert LangString.comparable?(
LangString.new("foo", language: "de"),
RDF.string("foo")) == false
end
test "compare/2" do
Enum.each @valid, fn {input, {_, language}} ->
assert LangString.compare(

View file

@ -140,6 +140,15 @@ defmodule RDF.Literal.XSDTest do
end
end)
Enum.each(@examples, fn {rdf_datatype, xsd_datatype, value_type} ->
value = value_type |> value() |> List.first()
@tag rdf_datatype: rdf_datatype, xsd_datatype: xsd_datatype, value: value
test "#{rdf_datatype}.comparable?/2 (#{inspect value})", %{rdf_datatype: rdf_datatype, value: value} do
literal = rdf_datatype.new(value)
assert rdf_datatype.comparable?(literal, literal) == true
end
end)
describe "cast/1" do
test "when given a literal with the same datatype" do
assert RDF.XSD.String.new("foo") |> RDF.XSD.String.cast() == RDF.XSD.String.new("foo")