Skip to content

Upgrading to RDF.ex 0.8

Marcel Otto edited this page Jun 2, 2020 · 2 revisions

RDF literals and their datatypes were completely redesigned in RDF.ex 0.8. For an introduction on how literals work now, read the updated page on literals in the guide and for a complete list of the changes, the CHANGELOG.

Moved datatype constructor functions and modules

All the datatype modules, like RDF.Integer, and all their constructor functions, like RDF.integer, were moved from top-level RDF namespace into the RDF.XSD namespace.

So, things like these:

RDF.Decimal.new(3.14)
RDF.decimal(3.14)

must be replaced with this something like this

alias RDF.XSD

XSD.Decimal.new(3.14)
XSD.decimal(3.14)

Be careful with aliasing RDF.XSD if you've previously used this alias for RDF.NS.XSD. This module for the XSD namespace is still independently present. I recommend aliasing RDF.NS instead and use NS.XSD.integer for example instead, to make it explicit that this is the namespace module, used to resolve to IRIs of the XSD namespace.

An alternative without the RDF.NS.XSD namespace at all, would be to use the id/0 function of the RDF.Literal.Datatype modules, which also returns the IRI as a RDF.IRI. So, [XSD.Integer.id](http://xsd.integer.id) would lead to the same result as NS.XSD.integer.

Note that RDF.LangString is still where it was.

RDF.Literal structure

The structure of RDF.Literal was changed and no longer contains the value anymore directly. Instead, RDF.Literals now consist of a single literal field holding another dedicated structure for the datatype of the literal.

So, accessing the values of literals like here:

string = ~L"foo"
integer = RDF.integer(42)

string.value  # => "foo"
integer.value # => 42

should happen now via the value/1 function, either the general RDF.Literal.value/1 function or one of the value/1 functions on the RDF.Literal.Datatype modules which do an implicit type check by returning nil when the literal is not of the correct type (taking also derivations into consideration).

string = ~L"foo"
integer = XSD.integer(42)

string |> RDF.Literal.value()  # => "foo"
string |> XSD.String.value()   # => "foo"
string |> XSD.Integer.value()  # => nil
integer |> XSD.Integer.value() # => 42

Besides being more memory-efficient (since literals no longer consist of all possible fields a literal might have), the new RDF.Literal structure allows pattern matching now on the datatype of literals.

So, in many places where you previously had to use conditionals on the datatype of literals you can now pattern match and for example introduce dedicated function clauses.

def fun(%RDF.Literal{literal: %XSD.Integer{}} = literal) do
  # ...
end

Higher-level literal functions

General higher-level functions are no longer offered on the RDF.Literal.Datatype modules, but only on the RDF.Literal module. This affects the matches?, less_than?, greater_than? functions.

So, this

RDF.String.matches?(literal, pattern)

must be replaced with this

RDF.Literal.matches?(literal, pattern)

The language option

The language option on the String.new/2 constructor is no longer supported, which means you'll have to either use the RDF.LangString.new/2 or the RDF.Literal.new/2 constructor.

Also, the language option on RDF.Literal.new/2 is no longer ignored if it's empty (nil or ""), so this either produces an invalid RDF.LangString now or, if another datatype is provided will fail with an ArgumentError.

These should fix most issues after an upgrade. If your code still not compiles or works after that, please refer to the CHANGELOG for other smaller changes or raise an issue.