Add RDF.Graph.delete_annotations/3 and delete_annotations opts
This commit is contained in:
parent
538663ddb5
commit
8469be877d
2 changed files with 250 additions and 9 deletions
|
@ -182,6 +182,10 @@ defmodule RDF.Graph do
|
|||
Also when the statements to be added are given as another `RDF.Graph`, the
|
||||
prefixes of this graph will be added. In case of conflicting prefix mappings
|
||||
the original prefix from `graph` will be kept.
|
||||
|
||||
RDF* annotations to be added to all of given statements can be specified with
|
||||
the `:annotate` keyword option and predicate-objects pairs as a tuple, list of
|
||||
tuples or a map.
|
||||
"""
|
||||
@spec add(t, input, keyword) :: t
|
||||
def add(graph, input, opts \\ [])
|
||||
|
@ -272,6 +276,11 @@ defmodule RDF.Graph do
|
|||
of this graph will be added. In case of conflicting prefix mappings the
|
||||
original prefix from `graph` will be kept.
|
||||
|
||||
RDF* annotations to be added to all of given statements can be specified with
|
||||
the `:annotate` keyword option and predicate-objects pairs as a tuple, list of
|
||||
tuples or a map. As with the actual asserted statements, the annotation will
|
||||
overwrite existing annotations.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
|
||||
|
@ -322,6 +331,11 @@ defmodule RDF.Graph do
|
|||
of this graph will be added. In case of conflicting prefix mappings the
|
||||
original prefix from `graph` will be kept.
|
||||
|
||||
RDF* annotations to be added to all of given statements can be specified with
|
||||
the `:annotate` keyword option and predicate-objects pairs as a tuple, list of
|
||||
tuples or a map. All exiting annotations of the asserted statements will be
|
||||
overwritten.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
|
||||
|
@ -365,11 +379,15 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Deletes statements from a `RDF.Graph`.
|
||||
|
||||
Note: When the statements to be deleted are given as another `RDF.Graph`,
|
||||
When the statements to be deleted are given as another `RDF.Graph`,
|
||||
the graph name must not match graph name of the graph from which the statements
|
||||
are deleted. If you want to delete only graphs with matching names, you can
|
||||
are deleted. If you want to delete only statements with matching graph names, you can
|
||||
use `RDF.Data.delete/2`.
|
||||
|
||||
The optional `:delete_annotations` keyword option allows to set which of
|
||||
annotations of the deleted statements should be deleted also.
|
||||
Any of the possible values of `delete_annotations/3` can be provided here.
|
||||
By default no annotations of the deleted statements will be removed.
|
||||
"""
|
||||
@spec delete(t, input, keyword) :: t
|
||||
def delete(graph, input, opts \\ [])
|
||||
|
@ -421,28 +439,82 @@ defmodule RDF.Graph do
|
|||
else
|
||||
graph
|
||||
end
|
||||
|> do_delete_delete_annotations(subject, input, opts)
|
||||
end
|
||||
|
||||
defp do_delete_delete_annotations(graph, subject, statements, opts) do
|
||||
if delete_annotations = Keyword.get(opts, :delete_annotations, false) do
|
||||
delete_annotations(graph, Description.new(subject, init: statements), delete_annotations)
|
||||
else
|
||||
graph
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes RDF-star annotations of a given set of statements.
|
||||
|
||||
The `statements` can be given in any input form (see `add/3`).
|
||||
|
||||
If `true` is given as the third argument or is `delete_annotations/2` is used,
|
||||
all annotations of the given `statements` are deleted.
|
||||
|
||||
If a single predicate or list of predicates is given only statements with
|
||||
these predicates from the annotations of the given `statements` are deleted.
|
||||
"""
|
||||
@spec delete_annotations(
|
||||
t,
|
||||
input,
|
||||
boolean | Statement.coercible_predicate() | [Statement.coercible_predicate()]
|
||||
) :: t
|
||||
def delete_annotations(graph, statements, delete \\ true)
|
||||
def delete_annotations(graph, _, false), do: graph
|
||||
|
||||
def delete_annotations(graph, statements, true) do
|
||||
delete_descriptions(graph, statements |> new() |> triples())
|
||||
end
|
||||
|
||||
def delete_annotations(graph, statements, predicates) do
|
||||
statements
|
||||
|> new()
|
||||
|> Enum.reduce(graph, fn triple, graph ->
|
||||
update(graph, triple, &Description.delete_predicates(&1, predicates))
|
||||
end)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Deletes all statements with the given `subjects`.
|
||||
|
||||
If `subjects` contains subjects that are not in `graph`, they're simply ignored.
|
||||
|
||||
The optional `:delete_annotations` keyword option allows to set which of
|
||||
annotations of the deleted statements should be deleted also.
|
||||
Any of the possible values of `delete_annotations/3` can be provided here.
|
||||
By default no annotations of the deleted statements will be removed.
|
||||
"""
|
||||
@spec delete_descriptions(
|
||||
t,
|
||||
Statement.coercible_subject() | [Statement.coercible_subject()]
|
||||
Statement.coercible_subject() | [Statement.coercible_subject()],
|
||||
keyword
|
||||
) :: t
|
||||
def delete_descriptions(graph, subjects)
|
||||
def delete_descriptions(graph, subjects, opts \\ [])
|
||||
|
||||
def delete_descriptions(%__MODULE__{} = graph, subjects) when is_list(subjects) do
|
||||
Enum.reduce(subjects, graph, &delete_descriptions(&2, &1))
|
||||
def delete_descriptions(%__MODULE__{} = graph, subjects, opts) when is_list(subjects) do
|
||||
Enum.reduce(subjects, graph, &delete_descriptions(&2, &1, opts))
|
||||
end
|
||||
|
||||
def delete_descriptions(%__MODULE__{} = graph, subject) do
|
||||
%__MODULE__{graph | descriptions: Map.delete(graph.descriptions, RDF.coerce_subject(subject))}
|
||||
def delete_descriptions(%__MODULE__{} = graph, subject, opts) do
|
||||
case Map.pop(graph.descriptions, RDF.coerce_subject(subject)) do
|
||||
{nil, _} ->
|
||||
graph
|
||||
|
||||
{deleted_description, descriptions} ->
|
||||
%__MODULE__{graph | descriptions: descriptions}
|
||||
|> delete_annotations(deleted_description, Keyword.get(opts, :delete_annotations, false))
|
||||
end
|
||||
end
|
||||
|
||||
defdelegate delete_subjects(graph, subjects), to: __MODULE__, as: :delete_descriptions
|
||||
defdelegate delete_subjects(graph, subjects, opts), to: __MODULE__, as: :delete_descriptions
|
||||
|
||||
@doc """
|
||||
Updates the description of the `subject` in `graph` with the given function.
|
||||
|
|
|
@ -473,14 +473,183 @@ defmodule RDF.Star.Graph.Test do
|
|||
end
|
||||
end
|
||||
|
||||
describe "delete_annotations/3" do
|
||||
test "with false, no annotations are deleted" do
|
||||
graph = Graph.add(graph(), statement(), annotate: {EX.p(), EX.O})
|
||||
assert Graph.delete_annotations(graph, statement(), false) == graph
|
||||
end
|
||||
|
||||
test "with true, all annotations are deleted (default)" do
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete_annotations(statement(), true) ==
|
||||
graph() |> Graph.add(statement())
|
||||
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete_annotations(statement()) ==
|
||||
graph() |> Graph.add(statement())
|
||||
end
|
||||
|
||||
test "with a single predicate" do
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: [{EX.p1(), EX.O1}, {EX.p2(), EX.O2}])
|
||||
|> Graph.delete_annotations(statement(), EX.p2()) ==
|
||||
Graph.add(graph(), statement(), annotate: {EX.p1(), EX.O1})
|
||||
|
||||
graph =
|
||||
graph()
|
||||
|> Graph.add({EX.S1, EX.P1, EX.O1})
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({EX.S3, EX.P3, EX.O3})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO})
|
||||
|> Graph.add({{EX.S3, EX.P3, EX.O3}, EX.AP, EX.AO})
|
||||
|
||||
assert Graph.delete_annotations(
|
||||
graph,
|
||||
[{EX.S1, EX.P1, EX.O1}, {EX.S3, EX.P3, EX.O3}],
|
||||
EX.AP
|
||||
) ==
|
||||
graph()
|
||||
|> Graph.add({EX.S1, EX.P1, EX.O1})
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({EX.S3, EX.P3, EX.O3})
|
||||
end
|
||||
|
||||
test "with a list of predicates" do
|
||||
graph =
|
||||
graph()
|
||||
|> Graph.add({EX.S1, EX.P1, EX.O1})
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({EX.S3, EX.P3, EX.O3})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, [EX.AO1, EX.AO2]})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO})
|
||||
|> Graph.add({{EX.S2, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
|> Graph.add({{EX.S3, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
|
||||
assert Graph.delete_annotations(
|
||||
graph,
|
||||
[{EX.S1, EX.P1, EX.O1}, {EX.S3, EX.P3, EX.O3}],
|
||||
[EX.AP1, EX.AP2]
|
||||
) ==
|
||||
graph()
|
||||
|> Graph.add({EX.S1, EX.P1, EX.O1})
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({EX.S3, EX.P3, EX.O3})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO})
|
||||
|> Graph.add({{EX.S2, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
end
|
||||
end
|
||||
|
||||
test "delete/3" do
|
||||
assert graph_with_annotation() |> Graph.delete(star_statement()) == graph()
|
||||
end
|
||||
|
||||
test "delete_description/3" do
|
||||
describe "delete_annotations option on delete/3" do
|
||||
test "with false, no annotations are deleted (default)" do
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete(statement(), delete_annotations: false) ==
|
||||
graph() |> Graph.add({statement(), EX.p(), EX.O})
|
||||
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete(statement()) ==
|
||||
graph() |> Graph.add({statement(), EX.p(), EX.O})
|
||||
end
|
||||
|
||||
test "with true, all annotations are deleted" do
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete(statement(), delete_annotations: true) ==
|
||||
graph()
|
||||
end
|
||||
|
||||
test "annotations are even deleted, when the statements to be deleted are not present" do
|
||||
assert graph_with_annotation() |> Graph.delete(statement(), delete_annotations: true) ==
|
||||
graph()
|
||||
end
|
||||
|
||||
test "with predicates" do
|
||||
graph =
|
||||
graph()
|
||||
|> Graph.add({EX.S1, EX.P1, EX.O1})
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({EX.S3, EX.P3, EX.O3})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, [EX.AO1, EX.AO2]})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO})
|
||||
|> Graph.add({{EX.S2, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
|> Graph.add({{EX.S3, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
|
||||
assert Graph.delete(
|
||||
graph,
|
||||
[{EX.S1, EX.P1, EX.O1}, {EX.S3, EX.P3, EX.O3}],
|
||||
delete_annotations: [EX.AP1, EX.AP2]
|
||||
) ==
|
||||
graph()
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO})
|
||||
|> Graph.add({{EX.S2, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
|
||||
graph =
|
||||
graph()
|
||||
|> Graph.add(%{EX.S1 => %{EX.P1 => EX.O1, EX.P2 => EX.O2}},
|
||||
annotate: %{EX.AP1 => EX.AO1}
|
||||
)
|
||||
|
||||
assert Graph.delete(graph, {EX.S1, %{EX.P1 => EX.O1}}, delete_annotations: [EX.AP1, EX.AP2]) ==
|
||||
graph()
|
||||
|> Graph.add({EX.S1, EX.P2, EX.O2})
|
||||
|> Graph.add({{EX.S1, EX.P2, EX.O2}, EX.AP1, EX.AO1})
|
||||
end
|
||||
end
|
||||
|
||||
test "delete_descriptions/3" do
|
||||
assert graph_with_annotation() |> Graph.delete_descriptions(statement()) == graph()
|
||||
end
|
||||
|
||||
describe "delete_annotations option on delete_descriptions/3" do
|
||||
test "with false, no annotations are deleted (default)" do
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete_descriptions(EX.S, delete_annotations: false) ==
|
||||
graph() |> Graph.add({statement(), EX.p(), EX.O})
|
||||
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete_descriptions(EX.S) ==
|
||||
graph() |> Graph.add({statement(), EX.p(), EX.O})
|
||||
end
|
||||
|
||||
test "with true, all annotations are deleted" do
|
||||
assert graph()
|
||||
|> Graph.add(statement(), annotate: {EX.p(), EX.O})
|
||||
|> Graph.delete_descriptions(EX.S, delete_annotations: true) ==
|
||||
graph()
|
||||
end
|
||||
|
||||
test "with predicates" do
|
||||
graph =
|
||||
graph()
|
||||
|> Graph.add({EX.S1, EX.P1, EX.O1})
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({EX.S3, EX.P3, EX.O3})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, [EX.AO1, EX.AO2]})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO})
|
||||
|> Graph.add({{EX.S2, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
|> Graph.add({{EX.S3, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
|
||||
assert Graph.delete_descriptions(graph, [EX.S1, EX.S3], delete_annotations: [EX.AP1, EX.AP2]) ==
|
||||
graph()
|
||||
|> Graph.add({EX.S2, EX.P2, EX.O2})
|
||||
|> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO})
|
||||
|> Graph.add({{EX.S2, EX.P3, EX.O3}, EX.AP1, EX.AO})
|
||||
end
|
||||
end
|
||||
|
||||
test "update/3" do
|
||||
assert Graph.update(graph(), statement(), annotation(), fn _ -> raise "unexpected" end) ==
|
||||
graph_with_annotation()
|
||||
|
|
Loading…
Reference in a new issue