Add functions to remove all triples with annotations or quoted triples

This commit is contained in:
Marcel Otto 2021-11-14 14:30:30 +01:00
parent 7a1ee6833c
commit 9695e137ce
5 changed files with 156 additions and 1 deletions

View file

@ -831,6 +831,30 @@ defmodule RDF.Description do
}
end
@doc """
Removes all objects from a description which are quoted triples.
"""
@spec without_quoted_triples(t) :: t
def without_quoted_triples(%__MODULE__{} = description) do
%__MODULE__{
description
| predications:
Enum.reduce(description.predications, description.predications, fn
{predicate, objects}, predications ->
original_object_count = Enum.count(predications)
filtered_objects =
Enum.reject(objects, &match?({quoted_triple, _} when is_tuple(quoted_triple), &1))
case Enum.count(filtered_objects) do
0 -> Map.delete(predications, predicate)
^original_object_count -> predications
_ -> Map.put(predications, predicate, Map.new(filtered_objects))
end
end)
}
end
@doc """
Checks if two `RDF.Description`s are equal.

View file

@ -663,6 +663,26 @@ defmodule RDF.Graph do
@spec annotations(t) :: t
defdelegate annotations(graph), to: RDF.Star.Graph
@doc """
Returns the `RDF.Graph` without all annotations.
Note: This function excludes only triples where the subject is a quoted triple.
If you want to exclude also triples where the object is a quoted triple,
you'll have to use `RDF.Graph.without_quoted_triples/1`.
"""
@spec without_annotations(t) :: t
defdelegate without_annotations(graph), to: RDF.Star.Graph
@doc """
Returns the `RDF.Graph` without all statements including quoted triples on subject or object position.
This function is relatively costly, since it requires a full walk-through of all triples.
In many cases quoted triples are only used on subject position, where you can use
`RDF.Graph.without_annotations/1`.
"""
@spec without_quoted_triples(t) :: t
defdelegate without_quoted_triples(graph), to: RDF.Star.Graph
@doc """
Gets and updates the description of the given subject, in a single pass.

View file

@ -50,6 +50,40 @@ defmodule RDF.Star.Graph do
}
end
@spec without_annotations(Graph.t()) :: Graph.t()
def without_annotations(%Graph{} = graph) do
%Graph{
graph
| descriptions:
for(
non_annotation = {subject, _} when not is_tuple(subject) <- graph.descriptions,
into: %{},
do: non_annotation
)
}
end
@spec without_quoted_triples(Graph.t()) :: Graph.t()
def without_quoted_triples(%Graph{} = graph) do
%Graph{
graph
| descriptions:
Enum.reduce(graph.descriptions, graph.descriptions, fn
{subject, description}, descriptions when not is_tuple(subject) ->
description_without_quoted_triples = Description.without_quoted_triples(description)
if Enum.empty?(description_without_quoted_triples) do
Map.delete(descriptions, subject)
else
Map.put(descriptions, subject, description_without_quoted_triples)
end
{subject, _}, descriptions ->
Map.delete(descriptions, subject)
end)
}
end
@spec add_annotations(Graph.t(), Graph.input(), Description.input() | nil) :: Graph.t()
def add_annotations(graph, statements, annotations)

View file

@ -199,6 +199,36 @@ defmodule RDF.Star.Description.Test do
assert Description.describes?(annotation(), coercible_statement())
end
describe "without_quoted_triples/1" do
test "empty description" do
assert Description.without_quoted_triples(description()) == Description.new(description())
end
test "when the description has no quoted triples on object position" do
description =
Description.new(statement(),
init: [
{EX.ap1(), EX.ao()},
{EX.ap2(), EX.ao()}
]
)
assert Description.without_quoted_triples(description) == description
end
test "when the description has quoted triples" do
assert Description.new(statement(),
init: [
{EX.ap1(), EX.ao()},
{EX.ap1(), statement()},
{EX.ap2(), statement()}
]
)
|> Description.without_quoted_triples() ==
Description.new(statement(), init: {EX.ap1(), EX.ao()})
end
end
test "values/2" do
assert Description.new(statement(), init: {EX.ap(), statement()})
|> Description.values() == %{}

View file

@ -1757,7 +1757,8 @@ defmodule RDF.Star.GraphTest do
describe "annotations/1" do
test "when no annotations exist" do
assert Graph.annotations(graph()) == graph()
assert Graph.annotations(RDF.graph()) == RDF.graph()
assert Graph.annotations(RDF.graph(statement())) == RDF.graph()
end
test "when annotations exist" do
@ -1769,6 +1770,52 @@ defmodule RDF.Star.GraphTest do
end
end
describe "without_annotations/1" do
test "when no annotations exist" do
assert Graph.without_annotations(RDF.graph()) == RDF.graph()
assert Graph.without_annotations(RDF.graph(statement())) == RDF.graph(statement())
end
test "when annotations exist" do
assert Graph.without_annotations(graph_with_annotation()) == RDF.graph()
assert graph_with_annotation()
|> Graph.add(statement())
|> Graph.without_annotations() == RDF.graph(statement())
end
test "quoted triples on object position" do
assert Graph.without_annotations(graph_with_annotations()) == RDF.graph(object_annotation())
assert graph_with_annotations()
|> Graph.add(statement())
|> Graph.without_annotations() == RDF.graph([statement(), object_annotation()])
end
end
describe "without_quoted_triples/1" do
test "when no annotations exist" do
assert Graph.without_quoted_triples(RDF.graph()) == RDF.graph()
assert Graph.without_quoted_triples(RDF.graph(statement())) == RDF.graph(statement())
end
test "when annotations exist" do
assert Graph.without_quoted_triples(graph_with_annotation()) == RDF.graph()
assert graph_with_annotation()
|> Graph.add(statement())
|> Graph.without_quoted_triples() == RDF.graph(statement())
end
test "quoted triples on object position" do
assert Graph.without_quoted_triples(graph_with_annotations()) == RDF.graph()
assert graph_with_annotations()
|> Graph.add(statement())
|> Graph.without_quoted_triples() == RDF.graph(statement())
end
end
test "include?/3" do
assert Graph.include?(graph_with_annotations(), star_statement())
assert Graph.include?(graph_with_annotations(), {EX.As, EX.ap(), statement()})