Improve implementation of RDF.Graph.put/3
- fixes bugs with some combinations of possible inputs - simplify implementation - add opts
This commit is contained in:
parent
4dfc16a55a
commit
42f787836f
2 changed files with 116 additions and 90 deletions
130
lib/rdf/graph.ex
130
lib/rdf/graph.ex
|
@ -162,7 +162,6 @@ defmodule RDF.Graph do
|
|||
- a `RDF.Graph`
|
||||
- or a list with any combination of the former
|
||||
|
||||
|
||||
When the statements to be added are given as another `RDF.Graph`,
|
||||
the graph name must not match graph name of the graph to which the statements
|
||||
are added. As opposed to that, `RDF.Data.merge/2` will produce a `RDF.Dataset`
|
||||
|
@ -172,44 +171,44 @@ defmodule RDF.Graph do
|
|||
prefixes of this graph will be added. In case of conflicting prefix mappings
|
||||
the original prefix from `graph` will be kept.
|
||||
"""
|
||||
@spec add(t, input) :: t
|
||||
def add(graph, input)
|
||||
@spec add(t, input, keyword) :: t
|
||||
def add(graph, input, opts \\ [])
|
||||
|
||||
def add(graph, {subject, predications}),
|
||||
do: do_add(graph, coerce_subject(subject), predications)
|
||||
def add(graph, {subject, predications}, opts),
|
||||
do: do_add(graph, coerce_subject(subject), predications, opts)
|
||||
|
||||
def add(%__MODULE__{} = graph, {subject, _, _} = triple),
|
||||
do: do_add(graph, coerce_subject(subject), triple)
|
||||
def add(%__MODULE__{} = graph, {subject, _, _} = triple, opts),
|
||||
do: do_add(graph, coerce_subject(subject), triple, opts)
|
||||
|
||||
def add(graph, {subject, predicate, object, _}),
|
||||
do: add(graph, {subject, predicate, object})
|
||||
def add(graph, {subject, predicate, object, _}, opts),
|
||||
do: add(graph, {subject, predicate, object}, opts)
|
||||
|
||||
def add(%__MODULE__{} = graph, %Description{subject: subject} = description) do
|
||||
def add(%__MODULE__{} = graph, %Description{subject: subject} = description, opts) do
|
||||
if Description.count(description) > 0 do
|
||||
do_add(graph, subject, description)
|
||||
do_add(graph, subject, description, opts)
|
||||
else
|
||||
graph
|
||||
end
|
||||
end
|
||||
|
||||
def add(graph, %__MODULE__{descriptions: descriptions, prefixes: prefixes}) do
|
||||
def add(graph, %__MODULE__{descriptions: descriptions, prefixes: prefixes}, opts) do
|
||||
graph =
|
||||
Enum.reduce(descriptions, graph, fn {_, description}, graph ->
|
||||
add(graph, description)
|
||||
add(graph, description, opts)
|
||||
end)
|
||||
|
||||
if prefixes do
|
||||
add_prefixes(graph, prefixes, fn _, ns, _ -> ns end)
|
||||
add_prefixes(graph, prefixes, :ignore)
|
||||
else
|
||||
graph
|
||||
end
|
||||
end
|
||||
|
||||
def add(graph, input) when is_list(input) or is_map(input) do
|
||||
Enum.reduce(input, graph, &add(&2, &1))
|
||||
def add(graph, input, opts) when is_list(input) or is_map(input) do
|
||||
Enum.reduce(input, graph, &add(&2, &1, opts))
|
||||
end
|
||||
|
||||
defp do_add(%__MODULE__{descriptions: descriptions} = graph, subject, statements) do
|
||||
defp do_add(%__MODULE__{descriptions: descriptions} = graph, subject, statements, opts) do
|
||||
%__MODULE__{
|
||||
graph
|
||||
| descriptions:
|
||||
|
@ -217,9 +216,9 @@ defmodule RDF.Graph do
|
|||
descriptions,
|
||||
subject,
|
||||
# when new: create and initialize description with statements
|
||||
fn -> Description.new(subject, init: statements) end,
|
||||
fn -> Description.new(subject, Keyword.put(opts, :init, statements)) end,
|
||||
# when update: merge statements description
|
||||
fn description -> Description.add(description, statements) end
|
||||
fn description -> Description.add(description, statements, opts) end
|
||||
)
|
||||
}
|
||||
end
|
||||
|
@ -238,79 +237,36 @@ defmodule RDF.Graph do
|
|||
RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])
|
||||
|
||||
"""
|
||||
@spec put(t, input) :: t
|
||||
def put(graph, input)
|
||||
@spec put(t, input, keyword) :: t
|
||||
def put(graph, input, opts \\ [])
|
||||
|
||||
def put(graph, {subject, predications}),
|
||||
do: do_put(graph, coerce_subject(subject), predications)
|
||||
|
||||
def put(%__MODULE__{} = graph, {subject, _, _} = triple),
|
||||
do: do_put(graph, coerce_subject(subject), triple)
|
||||
|
||||
def put(graph, {subject, predicate, object, _}),
|
||||
do: put(graph, {subject, predicate, object})
|
||||
|
||||
def put(%__MODULE__{} = graph, %Description{subject: subject} = description) do
|
||||
if Description.count(description) > 0 do
|
||||
do_put(graph, subject, description)
|
||||
else
|
||||
graph
|
||||
end
|
||||
end
|
||||
|
||||
def put(graph, %__MODULE__{descriptions: descriptions, prefixes: prefixes}) do
|
||||
graph =
|
||||
Enum.reduce(descriptions, graph, fn {_, description}, graph ->
|
||||
put(graph, description)
|
||||
end)
|
||||
|
||||
if prefixes do
|
||||
add_prefixes(graph, prefixes, fn _, ns, _ -> ns end)
|
||||
else
|
||||
graph
|
||||
end
|
||||
end
|
||||
|
||||
def put(%__MODULE__{} = graph, input) when is_map(input) do
|
||||
Enum.reduce(input, graph, fn {subject, predications}, graph ->
|
||||
put(graph, {subject, predications})
|
||||
end)
|
||||
end
|
||||
|
||||
def put(%__MODULE__{} = graph, input) when is_list(input) do
|
||||
put(
|
||||
graph,
|
||||
Enum.group_by(
|
||||
input,
|
||||
fn
|
||||
{subject, _} -> subject
|
||||
{subject, _, _} -> subject
|
||||
{subject, _, _, _} -> subject
|
||||
%Description{subject: subject} -> subject
|
||||
end,
|
||||
fn
|
||||
{_, p, o} -> {p, o}
|
||||
{_, p, o, _} -> {p, o}
|
||||
{_, predications} -> predications
|
||||
%Description{} = description -> description
|
||||
end
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
defp do_put(%__MODULE__{descriptions: descriptions} = graph, subject, predications) do
|
||||
%__MODULE__{
|
||||
def put(%__MODULE__{} = graph, %__MODULE__{} = input, opts) do
|
||||
graph = %__MODULE__{
|
||||
graph
|
||||
| descriptions:
|
||||
lazy_map_update(
|
||||
descriptions,
|
||||
subject,
|
||||
# when new
|
||||
fn -> Description.new(subject, init: predications) end,
|
||||
# when updating
|
||||
fn current -> Description.put(current, predications) end
|
||||
Enum.reduce(
|
||||
input.descriptions,
|
||||
graph.descriptions,
|
||||
fn {subject, description}, descriptions ->
|
||||
Map.update(
|
||||
descriptions,
|
||||
subject,
|
||||
description,
|
||||
fn current -> Description.put(current, description, opts) end
|
||||
)
|
||||
end
|
||||
)
|
||||
}
|
||||
|
||||
if input.prefixes do
|
||||
add_prefixes(graph, input.prefixes, :ignore)
|
||||
else
|
||||
graph
|
||||
end
|
||||
end
|
||||
|
||||
def put(%__MODULE__{} = graph, input, opts) do
|
||||
put(graph, new() |> add(input, opts), opts)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
|
|
@ -174,7 +174,7 @@ defmodule RDF.GraphTest do
|
|||
assert Graph.change_name(named_graph(), nil).name == nil
|
||||
end
|
||||
|
||||
describe "add/2" do
|
||||
describe "add/3" do
|
||||
test "a proper triple" do
|
||||
assert Graph.add(graph(), {iri(EX.Subject), EX.predicate(), iri(EX.Object)})
|
||||
|> graph_includes_statement?({EX.Subject, EX.predicate(), EX.Object})
|
||||
|
@ -207,6 +207,50 @@ defmodule RDF.GraphTest do
|
|||
assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3})
|
||||
end
|
||||
|
||||
test "a list of subject-predications pairs" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
|
||||
|> RDF.Graph.add([
|
||||
{EX.S1,
|
||||
[
|
||||
{EX.P1, EX.O3},
|
||||
%{EX.P2 => [EX.O4]}
|
||||
]}
|
||||
])
|
||||
|
||||
assert Graph.triple_count(g) == 4
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.P1, EX.O1})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.P1, EX.O3})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.P2, EX.O4})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O2})
|
||||
end
|
||||
|
||||
test "a mixed list" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.p1(), EX.O1}, {EX.S2, EX.p2(), EX.O2}, {EX.S1, EX.p3(), EX.O3}])
|
||||
|> RDF.Graph.add([
|
||||
%{EX.S1 => {EX.p1(), EX.O41}},
|
||||
%{
|
||||
EX.S1 => %{EX.p1() => EX.O42},
|
||||
EX.S2 => %{EX.p2() => EX.O42}
|
||||
},
|
||||
{EX.S2, {EX.p2(), EX.O43}},
|
||||
[{EX.S2, {EX.p2(), EX.O44}}],
|
||||
EX.p2(EX.S2, EX.O45)
|
||||
])
|
||||
|
||||
assert Graph.triple_count(g) == 9
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O1})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p3(), EX.O3})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O41})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O42})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O42})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O43})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O44})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O45})
|
||||
end
|
||||
|
||||
test "a graph map" do
|
||||
g =
|
||||
Graph.add(graph(), %{
|
||||
|
@ -342,7 +386,7 @@ defmodule RDF.GraphTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "put/2" do
|
||||
describe "put/3" do
|
||||
test "a list of triples" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
|
||||
|
@ -379,7 +423,7 @@ defmodule RDF.GraphTest do
|
|||
assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O3})
|
||||
end
|
||||
|
||||
test "a list subject-predications pairs" do
|
||||
test "a list of subject-predications pairs" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
|
||||
|> RDF.Graph.put([
|
||||
|
@ -396,6 +440,30 @@ defmodule RDF.GraphTest do
|
|||
assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O2})
|
||||
end
|
||||
|
||||
test "a mixed list" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.p1(), EX.O1}, {EX.S2, EX.p2(), EX.O2}, {EX.S1, EX.p3(), EX.O3}])
|
||||
|> RDF.Graph.put([
|
||||
%{EX.S1 => {EX.p1(), EX.O41}},
|
||||
%{
|
||||
EX.S1 => %{EX.p1() => EX.O42},
|
||||
EX.S2 => %{EX.p2() => EX.O42}
|
||||
},
|
||||
{EX.S2, {EX.p2(), EX.O43}},
|
||||
[{EX.S2, {EX.p2(), EX.O44}}],
|
||||
EX.p2(EX.S2, EX.O45)
|
||||
])
|
||||
|
||||
assert Graph.triple_count(g) == 7
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p3(), EX.O3})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O41})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O42})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O42})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O43})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O44})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O45})
|
||||
end
|
||||
|
||||
test "a map" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.p1(), EX.O1}, {EX.S2, EX.p2(), EX.O2}])
|
||||
|
@ -405,7 +473,9 @@ defmodule RDF.GraphTest do
|
|||
EX.S3 => %{EX.p3() => EX.O3}
|
||||
})
|
||||
|
||||
assert Graph.triple_count(g) == 4
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p1(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S3, EX.p3(), EX.O3})
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue