Support value equality checks on RDF.Decimals
This commit is contained in:
parent
d06dcacb04
commit
2313e001fd
3 changed files with 28 additions and 6 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)},
|
||||
|
|
Loading…
Reference in a new issue