Extend serialization API with functions for reading from streams

This commit is contained in:
Marcel Otto 2020-11-04 12:18:04 +01:00
parent ff40022f6d
commit 6ad8d0da72
5 changed files with 61 additions and 6 deletions

View file

@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
### Added ### Added
- serialization functions for reading from and writing to streams
- `RDF.Dataset.prefixes/1` for getting an aggregated `RDF.PrefixMap` over all graphs - `RDF.Dataset.prefixes/1` for getting an aggregated `RDF.PrefixMap` over all graphs
- `RDF.PrefixMap.put/3` for adding a prefix mapping and overwrite an existing one - `RDF.PrefixMap.put/3` for adding a prefix mapping and overwrite an existing one
- `RDF.BlankNode.value/1` for getting the internal string representation of a blank node - `RDF.BlankNode.value/1` for getting the internal string representation of a blank node

View file

@ -6,7 +6,7 @@ defmodule RDF.Serialization.Decoder do
alias RDF.{Dataset, Graph} alias RDF.{Dataset, Graph}
@doc """ @doc """
Decodes a serialized `RDF.Graph` or `RDF.Dataset` from the given string. Decodes a serialized `RDF.Graph` or `RDF.Dataset` from a string.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs. dataset, or `{:error, reason}` if an error occurs.
@ -14,7 +14,7 @@ defmodule RDF.Serialization.Decoder do
@callback decode(String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} @callback decode(String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
@doc """ @doc """
Decodes a serialized `RDF.Graph` or `RDF.Dataset` from the given string. Decodes a serialized `RDF.Graph` or `RDF.Dataset` from a string.
As opposed to `decode`, it raises an exception if an error occurs. As opposed to `decode`, it raises an exception if an error occurs.
@ -23,6 +23,13 @@ defmodule RDF.Serialization.Decoder do
""" """
@callback decode!(String.t(), keyword) :: RDF.Graph.t() | RDF.Dataset.t() @callback decode!(String.t(), keyword) :: RDF.Graph.t() | RDF.Dataset.t()
@doc """
Decodes a serialized `RDF.Graph` or `RDF.Dataset` from a stream.
"""
@callback decode_from_stream(Enumerable.t(), keyword) :: RDF.Graph.t() | RDF.Dataset.t()
@optional_callbacks decode_from_stream: 2
defmacro __using__(_) do defmacro __using__(_) do
quote bind_quoted: [], unquote: true do quote bind_quoted: [], unquote: true do
@behaviour unquote(__MODULE__) @behaviour unquote(__MODULE__)
@ -37,6 +44,18 @@ defmodule RDF.Serialization.Decoder do
end end
defoverridable unquote(__MODULE__) defoverridable unquote(__MODULE__)
@before_compile unquote(__MODULE__)
end
end
defmacro __before_compile__(_env) do
quote do
@stream_support __MODULE__
|> Module.definitions_in()
|> Keyword.has_key?(:decode_from_stream)
@doc false
def stream_support?, do: @stream_support
end end
end end
end end

View file

@ -83,7 +83,7 @@ defmodule RDF.Serialization.Format do
""" """
@doc """ @doc """
Reads and decodes a serialized graph or dataset from a string. Deserializes a graph or dataset from a string.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs. dataset, or `{:error, reason}` if an error occurs.
@ -94,7 +94,7 @@ defmodule RDF.Serialization.Format do
def read_string(content, opts \\ []), do: Reader.read_string(decoder(), content, opts) def read_string(content, opts \\ []), do: Reader.read_string(decoder(), content, opts)
@doc """ @doc """
Reads and decodes a serialized graph or dataset from a string. Deserializes a graph or dataset from a string.
As opposed to `read_string/2`, it raises an exception if an error occurs. As opposed to `read_string/2`, it raises an exception if an error occurs.
@ -104,7 +104,15 @@ defmodule RDF.Serialization.Format do
def read_string!(content, opts \\ []), do: Reader.read_string!(decoder(), content, opts) def read_string!(content, opts \\ []), do: Reader.read_string!(decoder(), content, opts)
@doc """ @doc """
Reads and decodes a serialized graph or dataset from a file. Deserializes a graph or dataset from a stream.
#{@decoder_doc_ref}
"""
@spec read_stream(Enumerable.t(), keyword) :: Graph.t() | Dataset.t()
def read_stream(stream, opts \\ []), do: Reader.read_stream(decoder(), stream, opts)
@doc """
Deserializes a graph or dataset from a file.
It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or
dataset, or `{:error, reason}` if an error occurs. dataset, or `{:error, reason}` if an error occurs.
@ -115,7 +123,7 @@ defmodule RDF.Serialization.Format do
def read_file(file, opts \\ []), do: Reader.read_file(decoder(), file, opts) def read_file(file, opts \\ []), do: Reader.read_file(decoder(), file, opts)
@doc """ @doc """
Reads and decodes a serialized graph or dataset from a file. Deserializes a graph or dataset from a file.
As opposed to `read_file/2`, it raises an exception if an error occurs. As opposed to `read_file/2`, it raises an exception if an error occurs.

View file

@ -19,6 +19,15 @@ defmodule RDF.Serialization.Reader do
decoder.decode!(content, opts) decoder.decode!(content, opts)
end end
@spec read_stream(module, Enumerable.t(), keyword) :: Graph.t() | Dataset.t()
def read_stream(decoder, stream, opts \\ []) do
if decoder.stream_support?() do
decoder.decode_from_stream(stream, opts)
else
raise "#{inspect(decoder)} does not support streaming"
end
end
@spec read_file(module, Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} @spec read_file(module, Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any}
def read_file(decoder, file, opts \\ []) do def read_file(decoder, file, opts \\ []) do
case File.read(file) do case File.read(file) do

View file

@ -163,6 +163,24 @@ defmodule RDF.Serialization do
end end
end end
@doc """
Deserializes a graph or dataset from a stream.
The format must be specified with the `format` option and a format name or the
`media_type` option and the media type of the format.
Please refer to the documentation of the decoder of a RDF serialization format
for format-specific options.
"""
@spec read_stream(Enumerable.t(), keyword) :: Graph.t() | Dataset.t()
def read_stream(stream, opts) do
with {:ok, format} <- string_format(opts) do
format.read_stream(stream, opts)
else
{:error, error} -> raise error
end
end
@doc """ @doc """
Deserializes a graph or dataset from a file. Deserializes a graph or dataset from a file.