Limit and unify the forms of input on RDF.Graph functions

This commit is contained in:
Marcel Otto 2020-09-28 02:13:20 +02:00
parent 20a69964c7
commit a8c71df20b
6 changed files with 250 additions and 195 deletions

View file

@ -237,8 +237,6 @@ defmodule RDF do
defdelegate graph(), to: Graph, as: :new
defdelegate graph(arg), to: Graph, as: :new
defdelegate graph(arg1, arg2), to: Graph, as: :new
defdelegate graph(arg1, arg2, arg3), to: Graph, as: :new
defdelegate graph(arg1, arg2, arg3, arg4), to: Graph, as: :new
defdelegate dataset(), to: Dataset, as: :new
defdelegate dataset(arg), to: Dataset, as: :new

View file

@ -309,7 +309,7 @@ defmodule RDF.Dataset do
new_graphs =
graphs
|> Map.put(graph_context, Graph.put(graph, subject, predications))
|> Map.put(graph_context, Graph.put(graph, {subject, predications}))
%__MODULE__{name: name, graphs: new_graphs}
end

View file

@ -14,6 +14,7 @@ defmodule RDF.Graph do
@behaviour Access
import RDF.Statement
import RDF.Utils
alias RDF.{Description, IRI, PrefixMap, Statement}
@type graph_description :: %{Statement.subject() => Description.t()}
@ -25,8 +26,21 @@ defmodule RDF.Graph do
base_iri: IRI.t() | nil
}
@type input :: Statement.t() | Description.t() | t
@type input ::
Statement.coercible_t()
| {
Statement.coercible_subject(),
Description.input()
}
| Description.t()
| t
| %{
Statement.coercible_subject() => %{
Statement.coercible_predicate() =>
Statement.coercible_object() | [Statement.coercible_object()]
}
}
| list(input)
@type update_description_fun :: (Description.t() -> Description.t())
@type get_and_update_description_fun :: (Description.t() -> {Description.t(), input} | :pop)
@ -54,7 +68,7 @@ defmodule RDF.Graph do
RDF.Graph.new(name: EX.GraphName)
"""
@spec new(input | [input] | keyword) :: t
@spec new(input | keyword) :: t
def new(data_or_options)
def new(data_or_options)
@ -74,8 +88,8 @@ defmodule RDF.Graph do
The initial RDF triples can be provided
- as a single statement tuple
- an `RDF.Description`
- an `RDF.Graph`
- a `RDF.Description`
- a `RDF.Graph`
- or a list with any combination of the former
Available options:
@ -97,7 +111,7 @@ defmodule RDF.Graph do
RDF.Graph.new({EX.S, EX.p, EX.O}, name: EX.GraphName, base_iri: EX.base)
"""
@spec new(input | [input], keyword) :: t
@spec new(input, keyword) :: t
def new(data, options)
def new(%__MODULE__{} = graph, options) do
@ -112,26 +126,12 @@ defmodule RDF.Graph do
|> add(data)
end
@doc """
Creates an `RDF.Graph` with initial triples.
See `new/2` for available arguments.
"""
@spec new(
Statement.coercible_subject(),
Statement.coercible_predicate(),
Statement.coercible_object() | [Statement.coercible_object()],
keyword
) :: t
def new(subject, predicate, objects, options \\ []),
do: new([], options) |> add(subject, predicate, objects)
@doc """
Removes all triples from `graph`.
This function is useful for getting an empty graph based on the settings of
another graph, as this function keeps graph name name, base IRI and default
prefixes as they are and just removes the triples.
another graph, as this function keeps graph name, base IRI and default prefixes
as they are and just removes the triples.
"""
@spec clear(t) :: t
def clear(%__MODULE__{} = graph) do
@ -140,42 +140,35 @@ defmodule RDF.Graph do
@doc """
Adds triples to a `RDF.Graph`.
"""
@spec add(
t,
Statement.coercible_subject(),
Statement.coercible_predicate(),
Statement.coercible_object() | [Statement.coercible_object()]
) :: t
def add(%__MODULE__{} = graph, subject, predicate, objects),
do: add(graph, {subject, predicate, objects})
@doc """
Adds triples to a `RDF.Graph`.
The `input` can be provided
- as a single statement tuple
- a `RDF.Description`
- 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`
are added. As opposed to that, `RDF.Data.merge/2` will produce a `RDF.Dataset`
containing both graphs.
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.
"""
@spec add(t, input | [input]) :: t
def add(graph, triples)
@spec add(t, input) :: t
def add(graph, input)
def add(%__MODULE__{} = graph, {subject, _, _} = statement),
do: do_add(graph, coerce_subject(subject), statement)
def add(%__MODULE__{} = graph, {subject, _, _} = triple),
do: do_add(graph, coerce_subject(subject), triple)
def add(graph, {subject, predicate, object, _}),
do: add(graph, {subject, predicate, object})
def add(graph, triples) when is_list(triples) do
Enum.reduce(triples, graph, fn triple, graph ->
add(graph, triple)
end)
end
def add(graph, {subject, predications}),
do: do_add(graph, coerce_subject(subject), predications)
def add(%__MODULE__{} = graph, %Description{subject: subject} = description) do
if Description.count(description) > 0 do
@ -198,17 +191,23 @@ defmodule RDF.Graph do
end
end
def add(graph, statements) when is_list(statements) or is_map(statements) do
Enum.reduce(statements, graph, fn triple, graph ->
add(graph, triple)
end)
end
defp do_add(%__MODULE__{descriptions: descriptions} = graph, subject, statements) do
%__MODULE__{
graph
| descriptions:
Map.update(
lazy_map_update(
descriptions,
subject,
Description.new(subject) |> Description.add(statements),
fn description ->
Description.add(description, statements)
end
# when new: create and initialize description with statements
fn -> Description.new(subject, init: statements) end,
# when update: merge statements description
fn description -> Description.add(description, statements) end
)
}
end
@ -222,14 +221,17 @@ defmodule RDF.Graph do
## Examples
iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) |>
...> RDF.Graph.put([{EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])
iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
...> |> RDF.Graph.put([{EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}])
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 | [input]) :: t
@spec put(t, input) :: t
def put(graph, statements)
def put(graph, {subject, predications}),
do: do_put(graph, coerce_subject(subject), predications)
def put(%__MODULE__{} = graph, {subject, _, _} = statement),
do: do_put(graph, coerce_subject(subject), statement)
@ -254,93 +256,35 @@ defmodule RDF.Graph do
def put(%__MODULE__{} = graph, statements) when is_map(statements) do
Enum.reduce(statements, graph, fn {subject, predications}, graph ->
put(graph, subject, predications)
put(graph, {subject, predications})
end)
end
def put(%__MODULE__{} = graph, statements) when is_list(statements) do
put(graph, Enum.group_by(statements, &elem(&1, 0), fn {_, p, o} -> {p, o} end))
put(
graph,
Enum.group_by(statements, &elem(&1, 0), fn
{_, p, o} -> {p, o}
{_, predications} -> predications
end)
)
end
@doc """
Add statements to a `RDF.Graph`, overwriting all statements with the same subject and predicate.
"""
@spec put(
t,
Statement.coercible_subject(),
Description.statements() | [Description.statements()]
) :: t
def put(graph, subject, predications)
def put(%__MODULE__{descriptions: descriptions} = graph, subject, predications)
when is_list(predications) do
with subject = coerce_subject(subject) do
# TODO: Can we reduce this case also to do_put somehow? Only the initializer of Map.update differs ...
%__MODULE__{
graph
| descriptions:
Map.update(
descriptions,
subject,
Description.new(subject) |> Description.add(predications),
fn current ->
Description.put(current, predications)
end
)
}
end
end
def put(graph, subject, {_predicate, _objects} = predications),
do: put(graph, subject, [predications])
defp do_put(%__MODULE__{descriptions: descriptions} = graph, subject, statements) do
defp do_put(%__MODULE__{descriptions: descriptions} = graph, subject, predications) do
%__MODULE__{
graph
| descriptions:
Map.update(
lazy_map_update(
descriptions,
subject,
Description.new(subject) |> Description.add(statements),
fn current ->
Description.put(current, statements)
end
# when new
fn -> Description.new(subject, init: predications) end,
# when updating
fn current -> Description.put(current, predications) end
)
}
end
@doc """
Add statements to a `RDF.Graph`, overwriting all statements with the same subject and predicate.
## Examples
iex> RDF.Graph.new(EX.S, EX.P, EX.O1) |> RDF.Graph.put(EX.S, EX.P, EX.O2)
RDF.Graph.new(EX.S, EX.P, EX.O2)
iex> RDF.Graph.new(EX.S, EX.P1, EX.O1) |> RDF.Graph.put(EX.S, EX.P2, EX.O2)
RDF.Graph.new([{EX.S, EX.P1, EX.O1}, {EX.S, EX.P2, EX.O2}])
"""
@spec put(
t,
Statement.coercible_subject(),
Statement.coercible_predicate(),
Statement.coercible_object() | [Statement.coercible_object()]
) :: t
def put(%__MODULE__{} = graph, subject, predicate, objects),
do: put(graph, {subject, predicate, objects})
@doc """
Deletes statements from a `RDF.Graph`.
"""
@spec delete(
t,
Statement.coercible_subject(),
Statement.coercible_predicate(),
Statement.coercible_object() | [Statement.coercible_object()]
) :: t
def delete(graph, subject, predicate, object),
do: delete(graph, {subject, predicate, object})
@doc """
Deletes statements from a `RDF.Graph`.
@ -356,12 +300,15 @@ defmodule RDF.Graph do
def delete(%__MODULE__{} = graph, {subject, _, _} = triple),
do: do_delete(graph, coerce_subject(subject), triple)
def delete(graph, {subject, predications}),
do: do_delete(graph, coerce_subject(subject), predications)
def delete(graph, {subject, predicate, object, _}),
do: delete(graph, {subject, predicate, object})
def delete(%__MODULE__{} = graph, triples) when is_list(triples) do
Enum.reduce(triples, graph, fn triple, graph ->
delete(graph, triple)
def delete(%__MODULE__{} = graph, statements) when is_list(statements) or is_map(statements) do
Enum.reduce(statements, graph, fn statement, graph ->
delete(graph, statement)
end)
end
@ -375,8 +322,9 @@ defmodule RDF.Graph do
end
defp do_delete(%__MODULE__{descriptions: descriptions} = graph, subject, statements) do
with description when not is_nil(description) <- descriptions[subject],
new_description = Description.delete(description, statements) do
if description = descriptions[subject] do
new_description = Description.delete(description, statements)
%__MODULE__{
graph
| descriptions:
@ -387,7 +335,7 @@ defmodule RDF.Graph do
end
}
else
nil -> graph
graph
end
end
@ -448,7 +396,7 @@ defmodule RDF.Graph do
@spec update(
t,
Statement.coercible_subject(),
Description.statements() | [Description.statements()] | nil,
Description.input() | nil,
update_description_fun
) :: t
def update(graph = %__MODULE__{}, subject, initial \\ nil, fun) do
@ -575,11 +523,11 @@ defmodule RDF.Graph do
## Examples
iex> RDF.Graph.new({EX.S, EX.P, EX.O}) |>
...> RDF.Graph.get_and_update(EX.S, fn current_description ->
...> {current_description, {EX.P, EX.NEW}}
...> end)
{RDF.Description.new({EX.S, EX.P, EX.O}), RDF.Graph.new({EX.S, EX.P, EX.NEW})}
iex> RDF.Graph.new({EX.S, EX.P, EX.O})
...> |> RDF.Graph.get_and_update(EX.S, fn current_description ->
...> {current_description, {EX.P, EX.NEW}}
...> end)
{RDF.Description.new(EX.S, init: {EX.P, EX.O}), RDF.Graph.new({EX.S, EX.P, EX.NEW})}
"""
@impl Access
@ -589,7 +537,7 @@ defmodule RDF.Graph do
with subject = coerce_subject(subject) do
case fun.(get(graph, subject)) do
{old_description, new_description} ->
{old_description, put(graph, subject, new_description)}
{old_description, put(graph, {subject, new_description})}
:pop ->
pop(graph, subject)
@ -792,16 +740,34 @@ defmodule RDF.Graph do
@doc """
Checks if the given statement exists within a `RDF.Graph`.
"""
@spec include?(t, Statement.t()) :: boolean
def include?(
%__MODULE__{descriptions: descriptions},
triple = {subject, _, _}
) do
with subject = coerce_subject(subject),
%Description{} <- description = descriptions[subject] do
Description.include?(description, triple)
@spec include?(t, input) :: boolean
def include?(%__MODULE__{} = graph, {subject, _, _} = triple),
do: do_include?(graph, coerce_subject(subject), triple)
def include?(graph, {subject, predicate, object, _}),
do: include?(graph, {subject, predicate, object})
def include?(graph, {subject, predications}),
do: do_include?(graph, coerce_subject(subject), predications)
def include?(%__MODULE__{} = graph, %Description{subject: subject} = description),
do: do_include?(graph, subject, description)
def include?(graph, %__MODULE__{} = other_graph) do
other_graph
|> descriptions()
|> Enum.all?(&include?(graph, &1))
end
def include?(graph, statements) when is_list(statements) or is_map(statements) do
Enum.all?(statements, &include?(graph, &1))
end
defp do_include?(%__MODULE__{descriptions: descriptions}, subject, statements) do
if description = descriptions[subject] do
Description.include?(description, statements)
else
_ -> false
false
end
end

View file

@ -22,6 +22,7 @@ defmodule RDF.Statement do
@type term_mapping :: (qualified_term -> any | nil)
@type t :: Triple.t() | Quad.t()
@type coercible_t :: Triple.coercible_t() | Quad.coercible_t()
@doc """
Creates a `RDF.Statement` tuple with proper RDF values.

16
lib/rdf/utils/utils.ex Normal file
View file

@ -0,0 +1,16 @@
defmodule RDF.Utils do
@moduledoc false
def lazy_map_update(map, key, init_fun, fun) do
case map do
%{^key => value} ->
Map.put(map, key, fun.(value))
%{} ->
Map.put(map, key, init_fun.())
other ->
:erlang.error({:badmap, other}, [map, key, init_fun, fun])
end
end
end

View file

@ -32,20 +32,12 @@ defmodule RDF.GraphTest do
g = Graph.new({EX.Subject, EX.predicate(), EX.Object})
assert unnamed_graph?(g)
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object})
g = Graph.new(EX.Subject, EX.predicate(), EX.Object)
assert unnamed_graph?(g)
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object})
end
test "creating a named graph with an initial triple" do
g = Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.GraphName)
assert named_graph?(g, iri(EX.GraphName))
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object})
g = Graph.new(EX.Subject, EX.predicate(), EX.Object, name: EX.GraphName)
assert named_graph?(g, iri(EX.GraphName))
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object})
end
test "creating an unnamed graph with a list of initial triples" do
@ -59,7 +51,7 @@ defmodule RDF.GraphTest do
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2})
g = Graph.new(EX.Subject, EX.predicate(), [EX.Object1, EX.Object2])
g = Graph.new({EX.Subject, EX.predicate(), [EX.Object1, EX.Object2]})
assert unnamed_graph?(g)
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object1})
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object2})
@ -76,7 +68,7 @@ defmodule RDF.GraphTest do
assert graph_includes_statement?(g, {EX.Subject, EX.predicate1(), EX.Object1})
assert graph_includes_statement?(g, {EX.Subject, EX.predicate2(), EX.Object2})
g = Graph.new(EX.Subject, EX.predicate(), [EX.Object1, EX.Object2], name: EX.GraphName)
g = Graph.new({EX.Subject, EX.predicate(), [EX.Object1, EX.Object2]}, name: EX.GraphName)
assert named_graph?(g, iri(EX.GraphName))
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object1})
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object2})
@ -107,17 +99,15 @@ defmodule RDF.GraphTest do
test "creating a named graph from another graph" do
g =
Graph.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}),
name: EX.GraphName
)
Graph.new({EX.Subject, EX.predicate(), EX.Object})
|> Graph.new(name: EX.GraphName)
assert named_graph?(g, iri(EX.GraphName))
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object})
g =
Graph.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.OtherGraphName),
name: EX.GraphName
)
Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.OtherGraphName)
|> Graph.new(name: EX.GraphName)
assert named_graph?(g, iri(EX.GraphName))
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object})
@ -175,19 +165,13 @@ defmodule RDF.GraphTest do
|> Graph.clear() == Graph.new(opts)
end
describe "add" do
describe "add/2" 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})
assert Graph.add(graph(), {iri(EX.Subject), EX.predicate(), iri(EX.Object)})
|> graph_includes_statement?({EX.Subject, EX.predicate(), EX.Object})
end
test "a coercible triple" do
assert Graph.add(graph(), "http://example.com/Subject", EX.predicate(), EX.Object)
|> graph_includes_statement?({EX.Subject, EX.predicate(), EX.Object})
test "a coerced triple" do
assert Graph.add(
graph(),
{"http://example.com/Subject", EX.predicate(), EX.Object}
@ -196,7 +180,7 @@ defmodule RDF.GraphTest do
end
test "a triple with multiple objects" do
g = Graph.add(graph(), EX.Subject1, EX.predicate1(), [EX.Object1, EX.Object2])
g = Graph.add(graph(), {EX.Subject1, EX.predicate1(), [EX.Object1, EX.Object2]})
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object2})
end
@ -214,7 +198,23 @@ defmodule RDF.GraphTest do
assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3})
end
test "a Description" do
test "a graph map" do
g =
Graph.add(graph(), %{
EX.Subject1 => [{EX.predicate1(), EX.Object1}, {EX.predicate2(), [EX.Object2]}],
EX.Subject3 => %{EX.predicate3() => EX.Object3}
})
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2(), EX.Object2})
assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3})
end
test "an empty map" do
assert Graph.add(graph(), %{}) == graph()
end
test "a description" do
g =
Graph.add(
graph(),
@ -235,7 +235,7 @@ defmodule RDF.GraphTest do
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate3(), EX.Object3})
end
test "a list of Descriptions" do
test "a list of descriptions" do
g =
Graph.add(graph(), [
Description.new(EX.Subject1, init: {EX.predicate1(), EX.Object1}),
@ -253,7 +253,7 @@ defmodule RDF.GraphTest do
assert Graph.add(g, {EX.Subject, EX.predicate(), EX.Object}) == g
end
test "a Graph" do
test "a graph" do
g =
Graph.add(
graph(),
@ -311,7 +311,7 @@ defmodule RDF.GraphTest do
test "preserves the name and prefixes when the data provided is not a graph" do
graph =
Graph.new(name: EX.GraphName, prefixes: %{ex: EX})
|> Graph.add(EX.Subject, EX.predicate(), EX.Object)
|> Graph.add({EX.Subject, EX.predicate(), EX.Object})
assert graph.name == RDF.iri(EX.GraphName)
assert graph.prefixes == PrefixMap.new(ex: EX)
@ -328,7 +328,7 @@ defmodule RDF.GraphTest do
end
end
describe "put" do
describe "put/2" do
test "a list of triples" do
g =
Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
@ -347,7 +347,38 @@ defmodule RDF.GraphTest do
assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O4})
end
test "a Description" do
test "a list subject-predications pairs" do
g =
Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}])
|> RDF.Graph.put([
{EX.S1,
[
{EX.P1, EX.O3},
%{EX.P2 => [EX.O4]}
]}
])
assert Graph.triple_count(g) == 3
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 map" do
g =
Graph.new([{EX.S1, EX.p1(), EX.O1}, {EX.S2, EX.p2(), EX.O2}])
|> Graph.put(%{
EX.S1 => [{EX.p1(), EX.O2}],
EX.S2 => %{EX.p1() => EX.O2},
EX.S3 => %{EX.p3() => EX.O3}
})
assert graph_includes_statement?(g, {EX.S1, EX.p1(), 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
test "a description" 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(
@ -362,7 +393,7 @@ defmodule RDF.GraphTest do
assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O2})
end
test "a Graph" do
test "a graph" do
g =
Graph.new([
{EX.S1, EX.P1, EX.O1},
@ -403,7 +434,7 @@ defmodule RDF.GraphTest do
test "preserves the name, base_iri and prefixes" do
graph =
Graph.new(name: EX.GraphName, prefixes: %{ex: EX}, base_iri: EX.base())
|> Graph.put(EX.Subject, EX.predicate(), EX.Object)
|> Graph.put({EX.Subject, EX.predicate(), EX.Object})
assert graph.name == RDF.iri(EX.GraphName)
assert graph.prefixes == PrefixMap.new(ex: EX)
@ -411,7 +442,7 @@ defmodule RDF.GraphTest do
end
end
describe "delete" do
describe "delete/2" do
setup do
{:ok,
graph1: Graph.new({EX.S, EX.p(), EX.O}),
@ -424,7 +455,7 @@ defmodule RDF.GraphTest do
])}
end
test "a single statement as a triple",
test "a triple",
%{graph1: graph1, graph2: graph2} do
assert Graph.delete(Graph.new(), {EX.S, EX.p(), EX.O}) == Graph.new()
assert Graph.delete(graph1, {EX.S, EX.p(), EX.O}) == Graph.new()
@ -436,15 +467,13 @@ defmodule RDF.GraphTest do
Graph.new({EX.S, EX.p(), EX.O2}, name: EX.Graph)
end
test "multiple statements with a triple with multiple objects",
%{graph1: graph1, graph2: graph2} do
test "a triple with multiple objects", %{graph1: graph1, graph2: graph2} do
assert Graph.delete(Graph.new(), {EX.S, EX.p(), [EX.O1, EX.O2]}) == Graph.new()
assert Graph.delete(graph1, {EX.S, EX.p(), [EX.O, EX.O2]}) == Graph.new()
assert Graph.delete(graph2, {EX.S, EX.p(), [EX.O1, EX.O2]}) == Graph.new(name: EX.Graph)
end
test "multiple statements with a list of triples",
%{graph1: graph1, graph2: graph2, graph3: graph3} do
test "a list of triples", %{graph1: graph1, graph2: graph2, graph3: graph3} do
assert Graph.delete(graph1, [{EX.S, EX.p(), EX.O}, {EX.S, EX.p(), EX.O2}]) == Graph.new()
assert Graph.delete(graph2, [{EX.S, EX.p(), EX.O1}, {EX.S, EX.p(), EX.O2}]) ==
@ -457,7 +486,23 @@ defmodule RDF.GraphTest do
]) == Graph.new({EX.S3, EX.p3(), ~L"bar"})
end
test "multiple statements with a Description",
test "a map", %{graph1: graph1, graph2: graph2, graph3: graph3} do
assert Graph.delete(graph1, %{EX.S => {EX.p(), [EX.O, EX.O2]}}) == Graph.new()
assert Graph.delete(graph2, %{EX.S => {EX.p(), [EX.O1, EX.O2]}}) ==
Graph.new(name: EX.Graph)
assert Graph.delete(
graph3,
%{
EX.S1 => %{EX.p1() => [EX.O1, EX.O2]},
EX.S2 => %{EX.p2() => EX.O3},
EX.S3 => %{EX.p3() => ~B<foo>}
}
) == Graph.new({EX.S3, EX.p3(), ~L"bar"})
end
test "a description",
%{graph1: graph1, graph2: graph2, graph3: graph3} do
assert Graph.delete(
graph1,
@ -476,7 +521,7 @@ defmodule RDF.GraphTest do
])
end
test "multiple statements with a Graph",
test "a graph",
%{graph1: graph1, graph2: graph2, graph3: graph3} do
assert Graph.delete(graph1, graph2) == graph1
assert Graph.delete(graph1, graph1) == Graph.new()
@ -499,15 +544,15 @@ defmodule RDF.GraphTest do
test "preserves the name and prefixes" do
graph =
Graph.new(EX.Subject, EX.predicate(), EX.Object, name: EX.GraphName, prefixes: %{ex: EX})
|> Graph.delete(EX.Subject, EX.predicate(), EX.Object)
Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.GraphName, prefixes: %{ex: EX})
|> Graph.delete({EX.Subject, EX.predicate(), EX.Object})
assert graph.name == RDF.iri(EX.GraphName)
assert graph.prefixes == PrefixMap.new(ex: EX)
end
end
describe "delete_subjects" do
describe "delete_subjects/2" do
setup do
{:ok,
graph1: Graph.new({EX.S, EX.p(), [EX.O1, EX.O2]}, name: EX.Graph),
@ -596,7 +641,7 @@ defmodule RDF.GraphTest do
assert Graph.new()
|> Graph.update(EX.S, {EX.P, EX.O}, fun) ==
Graph.new(EX.S, EX.P, EX.O)
Graph.new({EX.S, EX.P, EX.O})
assert Graph.new()
|> Graph.update(EX.S, fun) ==
@ -626,6 +671,33 @@ defmodule RDF.GraphTest do
assert Enum.count(graph.descriptions) == 1
end
test "include?/2" do
graph =
Graph.new([
{EX.S1, EX.p(), EX.O1},
{EX.S2, EX.p(), EX.O2}
])
assert Graph.include?(graph, {EX.S1, EX.p(), EX.O1})
assert Graph.include?(graph, {EX.S1, EX.p(), EX.O1, EX.Graph})
assert Graph.include?(graph, [{EX.S1, EX.p(), EX.O1}])
assert Graph.include?(graph, [
{EX.S1, EX.p(), EX.O1},
{EX.S2, EX.p(), EX.O2}
])
refute Graph.include?(graph, [
{EX.S1, EX.p(), EX.O1},
{EX.S2, EX.p(), EX.O3}
])
assert Graph.include?(graph, EX.S1 |> EX.p(EX.O1))
assert Graph.include?(graph, Graph.new(EX.S1 |> EX.p(EX.O1)))
assert Graph.include?(graph, graph)
end
test "values/1" do
assert Graph.new() |> Graph.values() == %{}
@ -710,7 +782,8 @@ defmodule RDF.GraphTest do
end
test "equal/2" do
assert Graph.new({EX.S, EX.p(), EX.O}) |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}))
assert Graph.new({EX.S, EX.p(), EX.O})
|> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}))
assert Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph1)
|> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph1))
@ -721,7 +794,8 @@ defmodule RDF.GraphTest do
assert Graph.new({EX.S, EX.p(), EX.O}, base_iri: EX.base())
|> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}, base_iri: EX.other_base()))
refute Graph.new({EX.S, EX.p(), EX.O}) |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O2}))
refute Graph.new({EX.S, EX.p(), EX.O})
|> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O2}))
refute Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph1)
|> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph2))