Add implementation of RDF.Datatype.cast/1 on all time-related datatypes

This commit is contained in:
Marcel Otto 2018-09-12 01:10:50 +02:00
parent 65a08c7754
commit e0635b42ad
7 changed files with 213 additions and 0 deletions

View file

@ -5,6 +5,8 @@ defmodule RDF.Date do
use RDF.Datatype, id: RDF.Datatype.NS.XSD.date
import RDF.Literal.Guards
@grammar ~r/\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/
@ -53,4 +55,35 @@ defmodule RDF.Date do
canonical_lexical(value) <> zone
end
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->
nil
is_xsd_date(datatype) ->
literal
is_xsd_datetime(datatype) ->
case literal.value do
%NaiveDateTime{} = datetime ->
datetime
|> NaiveDateTime.to_date()
|> new()
%DateTime{} = datetime ->
datetime
|> DateTime.to_date()
|> new(%{tz: RDF.DateTime.tz(literal)})
end
is_xsd_string(datatype) ->
literal.value
|> new()
true ->
nil
end
end
end

View file

@ -60,6 +60,34 @@ defmodule RDF.DateTime do
NaiveDateTime.to_iso8601(value)
end
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->
nil
is_xsd_datetime(datatype) ->
literal
is_xsd_date(datatype) ->
case literal.value do
{value, zone} ->
RDF.Date.canonical_lexical(value) <> "T00:00:00" <> zone
value ->
RDF.Date.canonical_lexical(value) <> "T00:00:00"
end
|> new()
is_xsd_string(datatype) ->
literal.value
|> new()
true ->
nil
end
end
def tz(%Literal{value: %NaiveDateTime{}}), do: ""
def tz(datetime_literal) do

View file

@ -109,4 +109,36 @@ defmodule RDF.Time do
end
end
def cast(%RDF.Literal{datatype: datatype} = literal) do
cond do
not RDF.Literal.valid?(literal) ->
nil
is_xsd_time(datatype) ->
literal
is_xsd_datetime(datatype) ->
case literal.value do
%NaiveDateTime{} = datetime ->
datetime
|> NaiveDateTime.to_time()
|> new()
%DateTime{} ->
[_date, time_with_zone] =
literal
|> RDF.DateTime.canonical_lexical_with_zone()
|> String.split("T", parts: 2)
new(time_with_zone)
end
is_xsd_string(datatype) ->
literal.value
|> new()
true ->
nil
end
end
end

View file

@ -73,4 +73,42 @@ defmodule RDF.DateTest do
end
end
describe "cast/1" do
test "casting a date returns the input as it is" do
assert RDF.date("2010-01-01") |> RDF.Date.cast() ==
RDF.date("2010-01-01")
end
test "casting a string" do
assert RDF.string("2010-01-01") |> RDF.Date.cast() ==
RDF.date("2010-01-01")
assert RDF.string("2010-01-01Z") |> RDF.Date.cast() ==
RDF.date("2010-01-01Z")
assert RDF.string("2010-01-01+01:00") |> RDF.Date.cast() ==
RDF.date("2010-01-01+01:00")
end
test "casting a datetime" do
assert RDF.date_time("2010-01-01T01:00:00") |> RDF.Date.cast() ==
RDF.date("2010-01-01")
assert RDF.date_time("2010-01-01T00:00:00Z") |> RDF.Date.cast() ==
RDF.date("2010-01-01Z")
assert RDF.date_time("2010-01-01T00:00:00+00:00") |> RDF.Date.cast() ==
RDF.date("2010-01-01Z")
assert RDF.date_time("2010-01-01T23:00:00+01:00") |> RDF.Date.cast() ==
RDF.date("2010-01-01+01:00")
end
test "with invalid literals" do
assert RDF.date("02010-01-00") |> RDF.Date.cast() == nil
assert RDF.date_time("02010-01-01T00:00:00") |> RDF.Date.cast() == nil
end
test "with literals of unsupported datatypes" do
assert RDF.false |> RDF.Date.cast() == nil
assert RDF.integer(1) |> RDF.Date.cast() == nil
assert RDF.decimal(3.14) |> RDF.Date.cast() == nil
end
end
end

View file

@ -123,6 +123,44 @@ defmodule RDF.DateTimeTest do
end
end
describe "cast/1" do
test "casting a datetime returns the input as it is" do
assert RDF.date_time("2010-01-01T12:34:56") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T12:34:56")
end
test "casting a string" do
assert RDF.string("2010-01-01T12:34:56") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T12:34:56")
assert RDF.string("2010-01-01T12:34:56Z") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T12:34:56Z")
assert RDF.string("2010-01-01T12:34:56+01:00") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T12:34:56+01:00")
end
test "casting a date" do
assert RDF.date("2010-01-01") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T00:00:00")
assert RDF.date("2010-01-01Z") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T00:00:00Z")
assert RDF.date("2010-01-01+00:00") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T00:00:00Z")
assert RDF.date("2010-01-01+01:00") |> RDF.DateTime.cast() ==
RDF.date_time("2010-01-01T00:00:00+01:00")
end
test "with invalid literals" do
assert RDF.date_time("02010-01-01T00:00:00") |> RDF.DateTime.cast() == nil
end
test "with literals of unsupported datatypes" do
assert RDF.false |> RDF.DateTime.cast() == nil
assert RDF.integer(1) |> RDF.DateTime.cast() == nil
assert RDF.decimal(3.14) |> RDF.DateTime.cast() == nil
end
end
test "canonical_lexical_with_zone/1" do
assert RDF.date_time(~N[2010-01-01T12:34:56]) |> DateTime.canonical_lexical_with_zone() == "2010-01-01T12:34:56"
assert RDF.date_time("2010-01-01T12:34:56") |> DateTime.canonical_lexical_with_zone() == "2010-01-01T12:34:56"

View file

@ -116,6 +116,12 @@ defmodule RDF.StringTest do
test "casting an IRI" do
assert RDF.iri("http://example.com") |> RDF.String.cast() == RDF.string("http://example.com")
end
test "with invalid literals" do
assert RDF.integer(3.14) |> RDF.Integer.cast() == nil
assert RDF.decimal("NAN") |> RDF.Integer.cast() == nil
assert RDF.double(true) |> RDF.Integer.cast() == nil
end
end
end

View file

@ -60,4 +60,42 @@ defmodule RDF.TimeTest do
end
end
describe "cast/1" do
test "casting a time returns the input as it is" do
assert RDF.time("01:00:00") |> RDF.Time.cast() ==
RDF.time("01:00:00")
end
test "casting a string" do
assert RDF.string("01:00:00") |> RDF.Time.cast() ==
RDF.time("01:00:00")
assert RDF.string("01:00:00Z") |> RDF.Time.cast() ==
RDF.time("01:00:00Z")
assert RDF.string("01:00:00+01:00") |> RDF.Time.cast() ==
RDF.time("01:00:00+01:00")
end
test "casting a datetime" do
assert RDF.date_time("2010-01-01T01:00:00") |> RDF.Time.cast() ==
RDF.time("01:00:00")
assert RDF.date_time("2010-01-01T00:00:00Z") |> RDF.Time.cast() ==
RDF.time("00:00:00Z")
assert RDF.date_time("2010-01-01T00:00:00+00:00") |> RDF.Time.cast() ==
RDF.time("00:00:00Z")
assert RDF.date_time("2010-01-01T23:00:00+01:00") |> RDF.Time.cast() ==
RDF.time("23:00:00+01:00")
end
test "with invalid literals" do
assert RDF.time("25:00:00") |> RDF.Time.cast() == nil
assert RDF.date_time("02010-01-01T00:00:00") |> RDF.Time.cast() == nil
end
test "with literals of unsupported datatypes" do
assert RDF.false |> RDF.Time.cast() == nil
assert RDF.integer(1) |> RDF.Time.cast() == nil
assert RDF.decimal(3.14) |> RDF.Time.cast() == nil
end
end
end