core: add RDF.Data.merge/2
This commit is contained in:
parent
06fb5a4044
commit
f5593aeef7
2 changed files with 227 additions and 7 deletions
101
lib/rdf/data.ex
101
lib/rdf/data.ex
|
@ -3,8 +3,26 @@ defprotocol RDF.Data do
|
|||
An abstraction over the different data structures for collections of RDF statements.
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Adds statements to a RDF data structure.
|
||||
|
||||
As opposed to the specific `add` functions on the RDF data structures, which
|
||||
always return the same structure type than the first argument, `merge` might
|
||||
result in another RDF data structure, eg. merging two `RDF.Description` with
|
||||
different subjects results in a `RDF.Graph` or adding a quad to a `RDF.Graph`
|
||||
with a different name than the graph context of the quad results in a
|
||||
`RDF.Dataset`. But it is always guaranteed that the resulting structure has
|
||||
a `RDF.Data` implementation.
|
||||
"""
|
||||
def merge(data, statements)
|
||||
|
||||
@doc """
|
||||
Deletes statements from a RDF data structure.
|
||||
|
||||
As opposed to the `delete` functions on RDF data structures directly, this
|
||||
function only deletes exactly matching structures.
|
||||
|
||||
TODO: rename this function to make the different semantics explicit
|
||||
"""
|
||||
def delete(data, statements)
|
||||
|
||||
|
@ -64,10 +82,40 @@ defprotocol RDF.Data do
|
|||
end
|
||||
|
||||
defimpl RDF.Data, for: RDF.Description do
|
||||
def merge(%RDF.Description{subject: subject} = description, {s, _, _} = triple) do
|
||||
with ^subject <- RDF.Statement.convert_subject(s) do
|
||||
RDF.Description.add(description, triple)
|
||||
else
|
||||
_ ->
|
||||
RDF.Graph.new(description)
|
||||
|> RDF.Graph.add(triple)
|
||||
end
|
||||
end
|
||||
|
||||
def merge(description, {_, _, _, _} = quad),
|
||||
do: RDF.Dataset.new(description) |> RDF.Dataset.add(quad)
|
||||
|
||||
def merge(%RDF.Description{subject: subject} = description,
|
||||
%RDF.Description{subject: other_subject} = other_description)
|
||||
when other_subject == subject,
|
||||
do: RDF.Description.add(description, other_description)
|
||||
|
||||
def merge(description, %RDF.Description{} = other_description),
|
||||
do: RDF.Graph.new(description) |> RDF.Graph.add(other_description)
|
||||
|
||||
def merge(description, %RDF.Graph{} = graph),
|
||||
do: RDF.Data.merge(graph, description)
|
||||
|
||||
def merge(description, %RDF.Dataset{} = dataset),
|
||||
do: RDF.Data.merge(dataset, description)
|
||||
|
||||
|
||||
def delete(%RDF.Description{subject: subject} = description,
|
||||
%RDF.Description{subject: other_subject})
|
||||
when subject != other_subject, do: description
|
||||
def delete(description, statements), do: RDF.Description.delete(description, statements)
|
||||
|
||||
|
||||
def pop(description), do: RDF.Description.pop(description)
|
||||
|
||||
def include?(description, statements),
|
||||
|
@ -75,11 +123,11 @@ defimpl RDF.Data, for: RDF.Description do
|
|||
|
||||
def statements(description), do: RDF.Description.statements(description)
|
||||
|
||||
def description(%RDF.Description{subject: subject} = description, requested_subject) do
|
||||
with ^subject <- RDF.Statement.convert_subject(requested_subject) do
|
||||
def description(%RDF.Description{subject: subject} = description, s) do
|
||||
with ^subject <- RDF.Statement.convert_subject(s) do
|
||||
description
|
||||
else
|
||||
_ -> RDF.Description.new(requested_subject)
|
||||
_ -> RDF.Description.new(s)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -94,10 +142,43 @@ defimpl RDF.Data, for: RDF.Description do
|
|||
def statement_count(description), do: RDF.Description.count(description)
|
||||
end
|
||||
|
||||
|
||||
defimpl RDF.Data, for: RDF.Graph do
|
||||
def merge(%RDF.Graph{name: name} = graph, {_, _, _, graph_context} = quad) do
|
||||
with ^name <- RDF.Statement.convert_graph_name(graph_context) do
|
||||
RDF.Graph.add(graph, quad)
|
||||
else
|
||||
_ ->
|
||||
RDF.Dataset.new(graph)
|
||||
|> RDF.Dataset.add(quad)
|
||||
end
|
||||
end
|
||||
|
||||
def merge(graph, {_, _, _} = triple),
|
||||
do: RDF.Graph.add(graph, triple)
|
||||
|
||||
def merge(description, {_, _, _, _} = quad),
|
||||
do: RDF.Dataset.new(description) |> RDF.Dataset.add(quad)
|
||||
|
||||
def merge(graph, %RDF.Description{} = description),
|
||||
do: RDF.Graph.add(graph, description)
|
||||
|
||||
def merge(%RDF.Graph{name: name} = graph,
|
||||
%RDF.Graph{name: other_name} = other_graph)
|
||||
when other_name == name,
|
||||
do: RDF.Graph.add(graph, other_graph)
|
||||
|
||||
def merge(graph, %RDF.Graph{} = other_graph),
|
||||
do: RDF.Dataset.new(graph) |> RDF.Dataset.add(other_graph)
|
||||
|
||||
def merge(graph, %RDF.Dataset{} = dataset),
|
||||
do: RDF.Data.merge(dataset, graph)
|
||||
|
||||
|
||||
def delete(%RDF.Graph{name: name} = graph, %RDF.Graph{name: other_name})
|
||||
when name != other_name, do: graph
|
||||
def delete(graph, statements), do: RDF.Graph.delete(graph, statements)
|
||||
|
||||
def pop(graph), do: RDF.Graph.pop(graph)
|
||||
|
||||
def include?(graph, statements), do: RDF.Graph.include?(graph, statements)
|
||||
|
@ -116,10 +197,24 @@ defimpl RDF.Data, for: RDF.Graph do
|
|||
def statement_count(graph), do: RDF.Graph.triple_count(graph)
|
||||
end
|
||||
|
||||
|
||||
defimpl RDF.Data, for: RDF.Dataset do
|
||||
def merge(dataset, {_, _, _} = triple),
|
||||
do: RDF.Dataset.add(dataset, triple)
|
||||
def merge(dataset, {_, _, _, _} = quad),
|
||||
do: RDF.Dataset.add(dataset, quad)
|
||||
def merge(dataset, %RDF.Description{} = description),
|
||||
do: RDF.Dataset.add(dataset, description)
|
||||
def merge(dataset, %RDF.Graph{} = graph),
|
||||
do: RDF.Dataset.add(dataset, graph)
|
||||
def merge(dataset, %RDF.Dataset{} = other_dataset),
|
||||
do: RDF.Dataset.add(dataset, other_dataset)
|
||||
|
||||
|
||||
def delete(%RDF.Dataset{name: name} = dataset, %RDF.Dataset{name: other_name})
|
||||
when name != other_name, do: dataset
|
||||
def delete(dataset, statements), do: RDF.Dataset.delete(dataset, statements)
|
||||
|
||||
def pop(dataset), do: RDF.Dataset.pop(dataset)
|
||||
|
||||
def include?(dataset, statements), do: RDF.Dataset.include?(dataset, statements)
|
||||
|
|
|
@ -14,24 +14,62 @@ defmodule RDF.DataTest do
|
|||
EX.S2
|
||||
|> EX.p2(EX.O3, EX.O4)
|
||||
)
|
||||
named_graph = %Graph{graph | name: uri(EX.NamedGraph)}
|
||||
dataset =
|
||||
Dataset.new
|
||||
|> Dataset.add(graph)
|
||||
|> Dataset.add((
|
||||
|> Dataset.add(
|
||||
Graph.new(EX.NamedGraph)
|
||||
|> Graph.add(description)
|
||||
|> Graph.add({EX.S3, EX.p3, EX.O5})
|
||||
|> Graph.add({EX.S, EX.p3, EX.O5})), EX.NamedGraph
|
||||
)
|
||||
|> Graph.add({EX.S, EX.p3, EX.O5}))
|
||||
{:ok,
|
||||
description: description,
|
||||
graph: graph,
|
||||
graph: graph, named_graph: named_graph,
|
||||
dataset: dataset,
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
describe "RDF.Data protocol implementation of RDF.Description" do
|
||||
test "merge of a single triple with different subject", %{description: description} do
|
||||
assert RDF.Data.merge(description, {EX.Other, EX.p1, EX.O3}) ==
|
||||
Graph.new(description) |> Graph.add({EX.Other, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a single triple with same subject", %{description: description} do
|
||||
assert RDF.Data.merge(description, {EX.S, EX.p1, EX.O3}) ==
|
||||
Description.add(description, {EX.S, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a single quad", %{description: description} do
|
||||
assert RDF.Data.merge(description, {EX.Other, EX.p1, EX.O3, EX.Graph}) ==
|
||||
Dataset.new(description) |> Dataset.add({EX.Other, EX.p1, EX.O3, EX.Graph})
|
||||
assert RDF.Data.merge(description, {EX.S, EX.p1, EX.O3, EX.Graph}) ==
|
||||
Dataset.new(description) |> Dataset.add({EX.S, EX.p1, EX.O3, EX.Graph})
|
||||
end
|
||||
|
||||
test "merge of a description with different subject", %{description: description} do
|
||||
assert RDF.Data.merge(description, Description.new({EX.Other, EX.p1, EX.O3})) ==
|
||||
Graph.new(description) |> Graph.add({EX.Other, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a description with same subject", %{description: description} do
|
||||
assert RDF.Data.merge(description, Description.new({EX.S, EX.p1, EX.O3})) ==
|
||||
Description.add(description, {EX.S, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a graph", %{graph: graph} do
|
||||
assert RDF.Data.merge(Description.new({EX.Other, EX.p1, EX.O3}), graph) ==
|
||||
Graph.add(graph, {EX.Other, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a dataset", %{dataset: dataset} do
|
||||
assert RDF.Data.merge(Description.new({EX.Other, EX.p1, EX.O3}), dataset) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
|
||||
test "delete", %{description: description} do
|
||||
assert RDF.Data.delete(description, {EX.S, EX.p1, EX.O2}) ==
|
||||
Description.delete(description, {EX.S, EX.p1, EX.O2})
|
||||
|
@ -43,6 +81,7 @@ defmodule RDF.DataTest do
|
|||
%Description{description | subject: EX.Other}) == description
|
||||
end
|
||||
|
||||
|
||||
test "pop", %{description: description} do
|
||||
assert RDF.Data.pop(description) == Description.pop(description)
|
||||
end
|
||||
|
@ -97,6 +136,60 @@ defmodule RDF.DataTest do
|
|||
|
||||
|
||||
describe "RDF.Data protocol implementation of RDF.Graph" do
|
||||
test "merge of a single triple", %{graph: graph, named_graph: named_graph} do
|
||||
assert RDF.Data.merge(graph, {EX.Other, EX.p, EX.O}) ==
|
||||
Graph.add(graph, {EX.Other, EX.p, EX.O})
|
||||
assert RDF.Data.merge(named_graph, {EX.Other, EX.p, EX.O}) ==
|
||||
Graph.add(named_graph, {EX.Other, EX.p, EX.O})
|
||||
end
|
||||
|
||||
test "merge of a single quad with the same graph context",
|
||||
%{graph: graph, named_graph: named_graph} do
|
||||
assert RDF.Data.merge(graph, {EX.Other, EX.p, EX.O, nil}) ==
|
||||
Graph.add(graph, {EX.Other, EX.p, EX.O})
|
||||
assert RDF.Data.merge(named_graph, {EX.Other, EX.p, EX.O, EX.NamedGraph}) ==
|
||||
Graph.add(named_graph, {EX.Other, EX.p, EX.O})
|
||||
end
|
||||
|
||||
test "merge of a single quad with a different graph context",
|
||||
%{graph: graph, named_graph: named_graph} do
|
||||
assert RDF.Data.merge(graph, {EX.S, EX.p1, EX.O3, EX.NamedGraph}) ==
|
||||
Dataset.new(graph) |> Dataset.add({EX.S, EX.p1, EX.O3, EX.NamedGraph})
|
||||
assert RDF.Data.merge(named_graph, {EX.S, EX.p1, EX.O3, nil}) ==
|
||||
Dataset.new(named_graph) |> Dataset.add({EX.S, EX.p1, EX.O3, nil})
|
||||
end
|
||||
|
||||
test "merge of a description", %{graph: graph} do
|
||||
assert RDF.Data.merge(graph, Description.new({EX.Other, EX.p1, EX.O3})) ==
|
||||
Graph.add(graph, {EX.Other, EX.p1, EX.O3})
|
||||
assert RDF.Data.merge(graph, Description.new({EX.S, EX.p1, EX.O3})) ==
|
||||
Graph.add(graph, {EX.S, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a graph with the same name",
|
||||
%{graph: graph, named_graph: named_graph} do
|
||||
assert RDF.Data.merge(graph, Graph.add(graph, {EX.Other, EX.p1, EX.O3})) ==
|
||||
Graph.add(graph, {EX.Other, EX.p1, EX.O3})
|
||||
assert RDF.Data.merge(named_graph, Graph.add(named_graph, {EX.Other, EX.p1, EX.O3})) ==
|
||||
Graph.add(named_graph, {EX.Other, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a graph with a different name",
|
||||
%{graph: graph, named_graph: named_graph} do
|
||||
assert RDF.Data.merge(graph, named_graph) ==
|
||||
Dataset.new(graph) |> Dataset.add(named_graph)
|
||||
assert RDF.Data.merge(named_graph, graph) ==
|
||||
Dataset.new(named_graph) |> Dataset.add(graph)
|
||||
end
|
||||
|
||||
test "merge of a dataset", %{dataset: dataset} do
|
||||
assert RDF.Data.merge(Graph.new({EX.Other, EX.p1, EX.O3}), dataset) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3})
|
||||
assert RDF.Data.merge(Graph.new(EX.NamedGraph, {EX.Other, EX.p1, EX.O3}), dataset) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3, EX.NamedGraph})
|
||||
end
|
||||
|
||||
|
||||
test "delete", %{graph: graph} do
|
||||
assert RDF.Data.delete(graph, {EX.S, EX.p1, EX.O2}) ==
|
||||
Graph.delete(graph, {EX.S, EX.p1, EX.O2})
|
||||
|
@ -163,6 +256,38 @@ defmodule RDF.DataTest do
|
|||
|
||||
|
||||
describe "RDF.Data protocol implementation of RDF.Dataset" do
|
||||
test "merge of a single triple", %{dataset: dataset} do
|
||||
assert RDF.Data.merge(dataset, {EX.Other, EX.p, EX.O}) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p, EX.O})
|
||||
end
|
||||
|
||||
test "merge of a single quad", %{dataset: dataset} do
|
||||
assert RDF.Data.merge(dataset, {EX.Other, EX.p, EX.O, nil}) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p, EX.O})
|
||||
assert RDF.Data.merge(dataset, {EX.Other, EX.p, EX.O, EX.NamedGraph}) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p, EX.O, EX.NamedGraph})
|
||||
end
|
||||
|
||||
test "merge of a description", %{dataset: dataset} do
|
||||
assert RDF.Data.merge(dataset, Description.new({EX.Other, EX.p1, EX.O3})) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
test "merge of a graph", %{dataset: dataset} do
|
||||
assert RDF.Data.merge(dataset, Graph.new({EX.Other, EX.p1, EX.O3})) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3})
|
||||
assert RDF.Data.merge(dataset, Graph.new(EX.NamedGraph, {EX.Other, EX.p1, EX.O3})) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3, EX.NamedGraph})
|
||||
end
|
||||
|
||||
test "merge of a dataset", %{dataset: dataset} do
|
||||
assert RDF.Data.merge(dataset, Dataset.new({EX.Other, EX.p1, EX.O3})) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3})
|
||||
assert RDF.Data.merge(dataset, Dataset.new(EX.NamedDataset, {EX.Other, EX.p1, EX.O3})) ==
|
||||
Dataset.add(dataset, {EX.Other, EX.p1, EX.O3})
|
||||
end
|
||||
|
||||
|
||||
test "delete", %{dataset: dataset} do
|
||||
assert RDF.Data.delete(dataset, {EX.S, EX.p1, EX.O2}) ==
|
||||
Dataset.delete(dataset, {EX.S, EX.p1, EX.O2})
|
||||
|
|
Loading…
Reference in a new issue