Support value equality checks on RDF.Decimals

This commit is contained in:
Marcel Otto 2018-06-16 01:48:10 +02:00
parent d06dcacb04
commit 2313e001fd
3 changed files with 28 additions and 6 deletions

View file

@ -2,10 +2,10 @@ defmodule RDF.Decimal do
@moduledoc """
`RDF.Datatype` for XSD decimal.
"""
alias Elixir.Decimal, as: D
use RDF.Datatype, id: RDF.Datatype.NS.XSD.decimal
alias Elixir.Decimal, as: D
def build_literal_by_value(value, opts) when is_integer(value),
do: value |> D.new() |> build_literal(to_string(value), opts)
@ -67,4 +67,7 @@ defmodule RDF.Decimal do
defp canonical_decimal(%D{coef: coef, exp: exp} = decimal),
do: canonical_decimal(%{decimal | coef: Kernel.div(coef, 10), exp: exp + 1})
def equal_value?(left, right), do: RDF.Numeric.equal_value?(left, right)
end

View file

@ -6,6 +6,8 @@ defmodule RDF.Numeric do
alias RDF.Literal
alias RDF.Datatype.NS.XSD
alias Elixir.Decimal, as: D
@types MapSet.new [
XSD.integer,
XSD.decimal,
@ -35,6 +37,7 @@ defmodule RDF.Numeric do
"""
def type?(type), do: MapSet.member?(@types, type)
@xsd_decimal XSD.decimal
@doc """
Tests for numeric value equality of two numeric literals.
@ -48,18 +51,29 @@ defmodule RDF.Numeric do
"""
def equal_value?(left, right)
def equal_value?(%Literal{datatype: left_datatype} = left,
%Literal{datatype: right_datatype} = right) do
def equal_value?(%Literal{datatype: left_datatype, value: left},
%Literal{datatype: right_datatype, value: right})
when left_datatype == @xsd_decimal or right_datatype == @xsd_decimal,
do: equal_decimal_value?(left, right)
def equal_value?(%Literal{datatype: left_datatype, value: left},
%Literal{datatype: right_datatype, value: right})
do
if type?(left_datatype) and type?(right_datatype) do
# We rely here on Elixirs numeric equality comparison.
# TODO: There are probably problematic edge-case, which might require an
# TODO: implementation of XPath type promotion and subtype substitution
# - https://www.w3.org/TR/xpath-functions/#op.numeric
# - https://www.w3.org/TR/xpath20/#id-type-promotion-and-operator-mapping
Literal.canonical(left).value == Literal.canonical(right).value
left == right
end
end
def equal_value?(_, _), do: nil
defp equal_decimal_value?(%D{} = left, %D{} = right), do: D.equal?(left, right)
defp equal_decimal_value?(%D{} = left, right), do: equal_decimal_value?(left, D.new(right))
defp equal_decimal_value?(left, %D{} = right), do: equal_decimal_value?(D.new(left), right)
defp equal_decimal_value?(_, _), do: nil
end

View file

@ -126,12 +126,17 @@ defmodule RDF.EqualityTest do
]
@value_equal_numerics [
{RDF.integer("42"), RDF.integer("042")},
{RDF.double("+0"), RDF.double("-0")},
{RDF.integer("42"), RDF.double("42")},
{RDF.integer(42), RDF.double(42.0)},
{RDF.integer("42"), RDF.decimal("42")},
{RDF.integer(42), RDF.decimal(42.0)},
{RDF.double(3.14), RDF.decimal(3.14)},
{RDF.double("+0"), RDF.double("-0")},
{RDF.decimal("+0"), RDF.decimal("-0")},
]
@value_unequal_numerics [
{RDF.integer("1"), RDF.double("1.1")},
{RDF.integer("1"), RDF.decimal("1.1")},
]
@incomparable_numerics [
{RDF.string("42"), RDF.integer(42)},