From 7daf494fb9b40f15068f6d92ad01fbef0a75a57b Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Sat, 23 May 2020 00:31:15 +0200 Subject: [PATCH] Restore ability to cast RDF.IRIs to XSD.Strings and XSD.AnyURIs This is needed for SPARQL. --- lib/rdf/literal/datatype.ex | 10 ++++++---- lib/rdf/xsd/datatypes/any_uri.ex | 4 ++++ lib/rdf/xsd/datatypes/string.ex | 4 ++++ test/unit/xsd/datatypes/any_uri_test.exs | 5 +++++ test/unit/xsd/datatypes/string_test.exs | 4 ++++ 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/lib/rdf/literal/datatype.ex b/lib/rdf/literal/datatype.ex index b02cefa..6994844 100644 --- a/lib/rdf/literal/datatype.ex +++ b/lib/rdf/literal/datatype.ex @@ -27,14 +27,15 @@ defmodule RDF.Literal.Datatype do Casts a datatype literal of one type into a datatype literal of another type. This function is called by the auto-generated `cast/1` function on the implementations, which already deals with the basic cases. - So, implementations can assume the passed argument is a valid `RDF.Literal.Datatype` struct. + So, implementations can assume the passed argument is a valid `RDF.Literal.Datatype` struct, + a `RDF.IRI` or a `RDF.BlankNode`. If the given literal can not be converted into this datatype an implementation should return `nil`. A final catch-all clause should delegate to `super`. For example `RDF.XSD.Datatype`s will handle casting from derived datatypes in the default implementation. """ - @callback do_cast(literal) :: Literal.t() | nil + @callback do_cast(literal | RDF.IRI.t | RDF.BlankNode.t) :: Literal.t() | nil @doc """ Checks if the given `RDF.Literal` has the datatype for which the `RDF.Literal.Datatype` is implemented or is derived from it. @@ -231,14 +232,15 @@ defmodule RDF.Literal.Datatype do Implementations define the casting for a given value with the `c:do_cast/1` callback. """ - @spec cast(Literal.t | Literal.Datatype.literal) :: Literal.t() | nil + @spec cast(Literal.Datatype.literal | RDF.Term.t) :: Literal.t() | nil @dialyzer {:nowarn_function, cast: 1} def cast(literal_or_value) def cast(%Literal{literal: literal}), do: cast(literal) def cast(%__MODULE__{} = datatype_literal), do: if(valid?(datatype_literal), do: literal(datatype_literal)) def cast(%struct{} = datatype_literal) do - if Literal.datatype?(struct) and Literal.Datatype.valid?(datatype_literal) do + if (Literal.datatype?(struct) and Literal.Datatype.valid?(datatype_literal)) or + struct in [RDF.IRI, RDF.BlankNode] do case do_cast(datatype_literal) do %__MODULE__{} = literal -> if valid?(literal), do: literal(literal) %Literal{literal: %__MODULE__{}} = literal -> if valid?(literal), do: literal diff --git a/lib/rdf/xsd/datatypes/any_uri.ex b/lib/rdf/xsd/datatypes/any_uri.ex index b38d7c9..7f403da 100644 --- a/lib/rdf/xsd/datatypes/any_uri.ex +++ b/lib/rdf/xsd/datatypes/any_uri.ex @@ -60,6 +60,10 @@ defmodule RDF.XSD.AnyURI do def elixir_mapping(_, _), do: @invalid_value + @impl RDF.Literal.Datatype + def do_cast(%IRI{} = iri), do: new(iri.value) + def do_cast(value), do: super(value) + @impl RDF.Literal.Datatype def do_equal_value?(literal1, literal2) diff --git a/lib/rdf/xsd/datatypes/string.ex b/lib/rdf/xsd/datatypes/string.ex index 5dbaa2d..414366d 100644 --- a/lib/rdf/xsd/datatypes/string.ex +++ b/lib/rdf/xsd/datatypes/string.ex @@ -47,6 +47,10 @@ defmodule RDF.XSD.String do def elixir_mapping(value, _), do: to_string(value) @impl RDF.Literal.Datatype + def do_cast(literal_or_iri) + + def do_cast(%RDF.IRI{value: value}), do: new(value) + def do_cast(%datatype{} = literal) do cond do XSD.Decimal.datatype?(literal) -> diff --git a/test/unit/xsd/datatypes/any_uri_test.exs b/test/unit/xsd/datatypes/any_uri_test.exs index afc60d7..a666b60 100644 --- a/test/unit/xsd/datatypes/any_uri_test.exs +++ b/test/unit/xsd/datatypes/any_uri_test.exs @@ -34,5 +34,10 @@ defmodule RDF.XSD.AnyURITest do assert XSD.anyURI("http://example.com/") |> XSD.AnyURI.cast() == XSD.anyURI("http://example.com/") end + + test "casting an RDF.IRI" do + assert RDF.iri("http://example.com/") |> XSD.AnyURI.cast() == + XSD.anyURI("http://example.com/") + end end end diff --git a/test/unit/xsd/datatypes/string_test.exs b/test/unit/xsd/datatypes/string_test.exs index a411857..db7f6c0 100644 --- a/test/unit/xsd/datatypes/string_test.exs +++ b/test/unit/xsd/datatypes/string_test.exs @@ -127,6 +127,10 @@ defmodule RDF.XSD.StringTest do assert FloatUnitInterval.new(1.0) |> XSD.String.cast() == XSD.string("1") end + test "casting an IRI" do + assert RDF.iri("http://example.com") |> XSD.String.cast() == XSD.string("http://example.com") + end + test "with invalid literals" do assert XSD.integer(3.14) |> XSD.String.cast() == nil assert XSD.decimal("NAN") |> XSD.String.cast() == nil