Add :default_graph_name option to RDF.NQuads.Encoder
and use the graph name of an RDF.Graph as its default
This commit is contained in:
parent
c753a7a30e
commit
7859c4e46d
3 changed files with 138 additions and 45 deletions
14
CHANGELOG.md
14
CHANGELOG.md
|
@ -9,13 +9,21 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
|
|||
|
||||
### Added
|
||||
|
||||
- support for `RDF.PropertyMap` on `RDF.Statement.new/2` and `RDF.Statement.coerce/2`
|
||||
- Support for `RDF.PropertyMap` on `RDF.Statement.new/2` and `RDF.Statement.coerce/2`.
|
||||
- `RDF.Dataset.graph_count/1`
|
||||
- The `RDF.NQuads.Encoder` now supports a `:default_graph_name` option, which
|
||||
allow to specify the graph name to be used as the default for triples
|
||||
from a `RDF.Graph` or `RDF.Description`.
|
||||
|
||||
### Changed
|
||||
|
||||
- the `RDF.Turtle.Encoder` no longer supports the encoding of `RDF.Dataset`s; you'll have to
|
||||
aggregate a `RDF.Dataset` to a `RDF.Graph` on your own now
|
||||
- The `RDF.Turtle.Encoder` no longer supports the encoding of `RDF.Dataset`s.
|
||||
You'll have to aggregate a `RDF.Dataset` to a `RDF.Graph` on your own now.
|
||||
- The `RDF.NQuads.Encoder` now uses the `RDF.Graph.name/1` as the graph name for
|
||||
the triples of a `RDF.Graph`.
|
||||
Previously the triples of an `RDF.Graph` were always encoded as part of default
|
||||
graph. You can use the new `:default_graph_name` option and set it to `nil` to get
|
||||
the old behaviour.
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -5,57 +5,70 @@ defmodule RDF.NQuads.Encoder do
|
|||
As for all encoders of `RDF.Serialization.Format`s, you normally won't use these
|
||||
functions directly, but via one of the `write_` functions on the `RDF.NQuads`
|
||||
format module or the generic `RDF.Serialization` module.
|
||||
|
||||
## Options
|
||||
|
||||
- `:default_graph_name`: The graph name to be used as the default for triples
|
||||
from a `RDF.Graph` or `RDF.Description`. When the input to be encoded is a
|
||||
`RDF.Description` the default is `nil` for the default graph. In case of a
|
||||
`RDF.Graph` the default is the `RDF.Graph.name/1`. The option doesn't
|
||||
have any effect at all when the input to be encoded is a `RDF.Dataset`.
|
||||
"""
|
||||
|
||||
use RDF.Serialization.Encoder
|
||||
|
||||
alias RDF.Statement
|
||||
alias RDF.{Statement, Graph}
|
||||
|
||||
@impl RDF.Serialization.Encoder
|
||||
@callback encode(RDF.Data.t(), keyword) :: {:ok, String.t()} | {:error, any}
|
||||
def encode(data, _opts \\ []) do
|
||||
{:ok,
|
||||
data
|
||||
|> Enum.reduce([], &[statement(&1) | &2])
|
||||
|> Enum.reverse()
|
||||
|> Enum.join()}
|
||||
def encode(data, opts \\ []) do
|
||||
default_graph_name = default_graph_name(data, Keyword.get(opts, :default_graph_name, false))
|
||||
{:ok, Enum.map_join(data, &statement(&1, default_graph_name))}
|
||||
end
|
||||
|
||||
@impl RDF.Serialization.Encoder
|
||||
@spec stream(RDF.Data.t(), keyword) :: Enumerable.t()
|
||||
def stream(data, opts \\ []) do
|
||||
default_graph_name = default_graph_name(data, Keyword.get(opts, :default_graph_name, false))
|
||||
|
||||
case Keyword.get(opts, :mode, :string) do
|
||||
:string -> Stream.map(data, &statement(&1))
|
||||
:iodata -> Stream.map(data, &iolist_statement(&1))
|
||||
:string -> Stream.map(data, &statement(&1, default_graph_name))
|
||||
:iodata -> Stream.map(data, &iolist_statement(&1, default_graph_name))
|
||||
invalid -> raise "Invalid stream mode: #{invalid}"
|
||||
end
|
||||
end
|
||||
|
||||
@spec statement(Statement.t()) :: String.t()
|
||||
def statement(statement)
|
||||
defp default_graph_name(%Graph{} = graph, false), do: graph.name
|
||||
defp default_graph_name(_, none) when none in [false, nil], do: nil
|
||||
|
||||
def statement({subject, predicate, object, nil}) do
|
||||
statement({subject, predicate, object})
|
||||
defp default_graph_name(_, default_graph_name),
|
||||
do: Statement.coerce_graph_name(default_graph_name)
|
||||
|
||||
@spec statement(Statement.t(), Statement.graph_name()) :: String.t()
|
||||
def statement(statement, default_graph_name)
|
||||
|
||||
def statement({subject, predicate, object, nil}, _) do
|
||||
"#{term(subject)} #{term(predicate)} #{term(object)} .\n"
|
||||
end
|
||||
|
||||
def statement({subject, predicate, object, graph}) do
|
||||
def statement({subject, predicate, object, graph}, _) do
|
||||
"#{term(subject)} #{term(predicate)} #{term(object)} #{term(graph)} .\n"
|
||||
end
|
||||
|
||||
def statement({subject, predicate, object}) do
|
||||
"#{term(subject)} #{term(predicate)} #{term(object)} .\n"
|
||||
def statement({subject, predicate, object}, default_graph_name) do
|
||||
statement({subject, predicate, object, default_graph_name}, default_graph_name)
|
||||
end
|
||||
|
||||
defdelegate term(value), to: RDF.NTriples.Encoder
|
||||
|
||||
@spec iolist_statement(Statement.t()) :: iolist
|
||||
def iolist_statement(statement)
|
||||
@spec iolist_statement(Statement.t(), Statement.graph_name()) :: iolist
|
||||
def iolist_statement(statement, default_graph_name)
|
||||
|
||||
def iolist_statement({subject, predicate, object, nil}) do
|
||||
iolist_statement({subject, predicate, object})
|
||||
def iolist_statement({subject, predicate, object, nil}, _) do
|
||||
[iolist_term(subject), " ", iolist_term(predicate), " ", iolist_term(object), " .\n"]
|
||||
end
|
||||
|
||||
def iolist_statement({subject, predicate, object, graph}) do
|
||||
def iolist_statement({subject, predicate, object, graph}, _) do
|
||||
[
|
||||
iolist_term(subject),
|
||||
" ",
|
||||
|
@ -68,8 +81,8 @@ defmodule RDF.NQuads.Encoder do
|
|||
]
|
||||
end
|
||||
|
||||
def iolist_statement({subject, predicate, object}) do
|
||||
[iolist_term(subject), " ", iolist_term(predicate), " ", iolist_term(object), " .\n"]
|
||||
def iolist_statement({subject, predicate, object}, default_graph_name) do
|
||||
iolist_statement({subject, predicate, object, default_graph_name}, default_graph_name)
|
||||
end
|
||||
|
||||
defdelegate iolist_term(value), to: RDF.NTriples.Encoder
|
||||
|
|
|
@ -24,6 +24,32 @@ defmodule RDF.NQuads.EncoderTest do
|
|||
assert NQuads.Encoder.encode!(Graph.new()) == ""
|
||||
end
|
||||
|
||||
test "graph name" do
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1}) |> NQuads.Encoder.encode!() ==
|
||||
"""
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
||||
"""
|
||||
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1}, name: EX.Graph) |> NQuads.Encoder.encode!() ==
|
||||
"""
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> <http://example.org/#Graph> .
|
||||
"""
|
||||
end
|
||||
|
||||
test "default_graph_name opt" do
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1})
|
||||
|> NQuads.Encoder.encode!(default_graph_name: EX.Graph) ==
|
||||
"""
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> <http://example.org/#Graph> .
|
||||
"""
|
||||
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1}, name: EX.Graph)
|
||||
|> NQuads.Encoder.encode!(default_graph_name: nil) ==
|
||||
"""
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
||||
"""
|
||||
end
|
||||
|
||||
test "statements with IRIs only" do
|
||||
assert NQuads.Encoder.encode!(
|
||||
Graph.new([
|
||||
|
@ -87,6 +113,20 @@ defmodule RDF.NQuads.EncoderTest do
|
|||
end
|
||||
end
|
||||
|
||||
test "serializing a description" do
|
||||
description = EX.S1 |> EX.p1(EX.O1)
|
||||
|
||||
assert NQuads.Encoder.encode!(description) ==
|
||||
"""
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
||||
"""
|
||||
|
||||
assert NQuads.Encoder.encode!(description, default_graph_name: EX.Graph) ==
|
||||
"""
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> <http://example.org/#Graph> .
|
||||
"""
|
||||
end
|
||||
|
||||
describe "serializing a dataset" do
|
||||
test "an empty dataset is serialized to an empty string" do
|
||||
assert NQuads.Encoder.encode!(Dataset.new()) == ""
|
||||
|
@ -143,27 +183,59 @@ defmodule RDF.NQuads.EncoderTest do
|
|||
end
|
||||
|
||||
describe "stream/2" do
|
||||
dataset =
|
||||
Dataset.new([
|
||||
{EX.S1, EX.p1(), EX.O1},
|
||||
{EX.S2, EX.p2(), RDF.bnode("foo"), EX.G},
|
||||
{EX.S3, EX.p3(), ~L"foo"},
|
||||
{EX.S3, EX.p3(), ~L"foo"en, EX.G}
|
||||
])
|
||||
test "a dataset" do
|
||||
dataset =
|
||||
Dataset.new([
|
||||
{EX.S1, EX.p1(), EX.O1},
|
||||
{EX.S2, EX.p2(), RDF.bnode("foo"), EX.G},
|
||||
{EX.S3, EX.p3(), ~L"foo"},
|
||||
{EX.S3, EX.p3(), ~L"foo"en, EX.G}
|
||||
])
|
||||
|
||||
expected_result = """
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
||||
<http://example.org/#S3> <http://example.org/#p3> "foo" .
|
||||
<http://example.org/#S2> <http://example.org/#p2> _:foo <http://example.org/#G> .
|
||||
<http://example.org/#S3> <http://example.org/#p3> "foo"@en <http://example.org/#G> .
|
||||
"""
|
||||
expected_result = """
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
||||
<http://example.org/#S3> <http://example.org/#p3> "foo" .
|
||||
<http://example.org/#S2> <http://example.org/#p2> _:foo <http://example.org/#G> .
|
||||
<http://example.org/#S3> <http://example.org/#p3> "foo"@en <http://example.org/#G> .
|
||||
"""
|
||||
|
||||
assert NQuads.Encoder.stream(dataset, mode: :string)
|
||||
|> stream_to_string() ==
|
||||
expected_result
|
||||
assert NQuads.Encoder.stream(dataset, mode: :string)
|
||||
|> stream_to_string() ==
|
||||
expected_result
|
||||
|
||||
assert NQuads.Encoder.stream(dataset, mode: :iodata)
|
||||
|> stream_to_string() ==
|
||||
expected_result
|
||||
assert NQuads.Encoder.stream(dataset, mode: :iodata)
|
||||
|> stream_to_string() ==
|
||||
expected_result
|
||||
end
|
||||
|
||||
test "a graph" do
|
||||
expected_unnamed_graph_result = """
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> .
|
||||
"""
|
||||
|
||||
expected_named_graph_result = """
|
||||
<http://example.org/#S1> <http://example.org/#p1> <http://example.org/#O1> <http://example.org/#Graph> .
|
||||
"""
|
||||
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1})
|
||||
|> NQuads.Encoder.stream(mode: :string)
|
||||
|> stream_to_string() ==
|
||||
expected_unnamed_graph_result
|
||||
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1})
|
||||
|> NQuads.Encoder.stream(mode: :iodata)
|
||||
|> stream_to_string() ==
|
||||
expected_unnamed_graph_result
|
||||
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1}, name: EX.Graph)
|
||||
|> NQuads.Encoder.stream(mode: :string)
|
||||
|> stream_to_string() ==
|
||||
expected_named_graph_result
|
||||
|
||||
assert Graph.new({EX.S1, EX.p1(), EX.O1}, name: EX.Graph)
|
||||
|> NQuads.Encoder.stream(mode: :iodata)
|
||||
|> stream_to_string() ==
|
||||
expected_named_graph_result
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue