diff --git a/lib/rdf/graph.ex b/lib/rdf/graph.ex index cda27fa..c894595 100644 --- a/lib/rdf/graph.ex +++ b/lib/rdf/graph.ex @@ -183,9 +183,10 @@ 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. - 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. + RDF-star annotations to be added to all of the given statements can be specified with + the `:add_annotations`, `:put_annotations` or `:put_annotation_properties` keyword + options. They have different addition semantics similar to the `add_annotations/3`, + `put_annotations/3` and `put_annotation_properties/3` counterparts. """ @spec add(t, input, keyword) :: t def add(graph, input, opts \\ []) @@ -211,7 +212,7 @@ defmodule RDF.Graph do # normalize the annotations here, so we don't have to do this repeatedly in do_add/4 opts = if annotation = Keyword.get(opts, :annotate) do - Keyword.put(opts, :annotate, normalize_annotation(annotation)) + Keyword.put(opts, :annotate, normalize_annotations(annotation)) else opts end @@ -253,22 +254,9 @@ defmodule RDF.Graph do fn description -> Description.add(description, statements, opts) end ) } - |> add_annotations(subject, statements, opts) + |> handle_annotation_additions(subject, statements, opts) end - defp add_annotations(graph, subject, statements, opts) do - if annotation = Keyword.get(opts, :annotate) |> normalize_annotation() do - Description.new(subject, init: statements) - |> Enum.reduce(graph, &add(&2, Description.change_subject(annotation, &1))) - else - graph - end - end - - defp normalize_annotation(nil), do: nil - defp normalize_annotation(%Description{} = annotation), do: annotation - defp normalize_annotation(annotation), do: Description.new(~B, init: annotation) - @doc """ Adds statements to a `RDF.Graph` overwriting existing statements with the subjects given in the `input` data. @@ -276,10 +264,10 @@ 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. + RDF-star annotations to be added to all of the given statements can be specified with + the `:add_annotations`, `:put_annotations` or `:put_annotation_properties` keyword + options. They have different addition semantics similar to the `add_annotations/3`, + `put_annotations/3` and `put_annotation_properties/3` counterparts. ## Examples @@ -309,19 +297,11 @@ defmodule RDF.Graph do else graph end - |> put_annotations(input, opts) + |> handle_annotation_additions(input, opts) end def put(%__MODULE__{} = graph, input, opts) do - put(graph, new() |> add(input, Keyword.delete_first(opts, :annotate)), opts) - end - - defp put_annotations(graph, input, opts) do - if annotation = Keyword.get(opts, :annotate) |> normalize_annotation() do - Enum.reduce(input, graph, &put(&2, Description.change_subject(annotation, &1))) - else - graph - end + put(graph, new() |> add(input, clear_annotation_opts(opts)), opts) end @doc """ @@ -331,10 +311,10 @@ 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. + RDF-star annotations to be added to all of the given statements can be specified with + the `:add_annotations`, `:put_annotations` or `:put_annotation_properties` keyword + options. They have different addition semantics similar to the `add_annotations/3`, + `put_annotations/3` and `put_annotation_properties/3` counterparts. ## Examples @@ -369,11 +349,11 @@ defmodule RDF.Graph do else graph end - |> put_annotations(input, opts) + |> handle_annotation_additions(input, opts) end def put_properties(%__MODULE__{} = graph, input, opts) do - put_properties(graph, new() |> add(input, Keyword.delete_first(opts, :annotate)), opts) + put_properties(graph, new() |> add(input, clear_annotation_opts(opts)), opts) end @doc """ @@ -450,37 +430,6 @@ defmodule RDF.Graph do 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`. @@ -516,6 +465,181 @@ defmodule RDF.Graph do defdelegate delete_subjects(graph, subjects), to: __MODULE__, as: :delete_descriptions defdelegate delete_subjects(graph, subjects, opts), to: __MODULE__, as: :delete_descriptions + # We've duplicated this logic from handle_annotation_additions/3 instead of delegating to it + # with Description.new(subject, init: statements), since we don't want to perform the + # creation of descriptions unnecessarily when no annotations are given. + defp handle_annotation_additions(graph, subject, statements, opts) do + cond do + Enum.empty?(opts) -> + graph + + put_annotations = Keyword.get(opts, :put_annotations) -> + put_annotations( + graph, + Description.new(subject, Keyword.put(opts, :init, statements)), + put_annotations + ) + + put_annotation_properties = Keyword.get(opts, :put_annotation_properties) -> + put_annotation_properties( + graph, + Description.new(subject, Keyword.put(opts, :init, statements)), + put_annotation_properties + ) + + add_annotations = Keyword.get(opts, :add_annotations) -> + add_annotations( + graph, + Description.new(subject, Keyword.put(opts, :init, statements)), + add_annotations + ) + + true -> + graph + end + end + + defp handle_annotation_additions(graph, statements, opts) do + cond do + Enum.empty?(opts) -> + graph + + put_annotations = Keyword.get(opts, :put_annotations) -> + put_annotations(graph, statements, put_annotations) + + put_annotation_properties = Keyword.get(opts, :put_annotation_properties) -> + put_annotation_properties(graph, statements, put_annotation_properties) + + add_annotations = Keyword.get(opts, :add_annotations) -> + add_annotations(graph, statements, add_annotations) + + true -> + graph + end + end + + defp clear_annotation_opts(opts), + do: Keyword.drop(opts, ~w[add_annotations put_annotations put_annotation_properties]a) + + @doc """ + Adds RDF-star annotations to the given set of statements. + + The set of `statements` can be given in any input form (see `add/3`). + + The predicate-objects pairs to be added as annotations can be given as a tuple, + a list of tuples or a map. + """ + @spec add_annotations(t, input, Description.input() | nil) :: t + def add_annotations(graph, statements, annotations) + + def add_annotations(%__MODULE__{} = graph, %rdf_struct{} = statements, annotations) + when rdf_struct in [__MODULE__, Description] do + if annotations = normalize_annotations(annotations) do + Enum.reduce(statements, graph, &add(&2, Description.change_subject(annotations, &1))) + else + graph + end + end + + def add_annotations(graph, statements, annotations) do + add_annotations(graph, new(statements), annotations) + end + + defp normalize_annotations(nil), do: nil + defp normalize_annotations(%Description{} = annotation), do: annotation + defp normalize_annotations(annotation), do: Description.new(~B, init: annotation) + + @doc """ + Adds RDF-star annotations to the given set of statements overwriting all existing annotations. + + The set of `statements` can be given in any input form (see `add/3`). + + The predicate-objects pairs to be added as annotations can be given as a tuple, + a list of tuples or a map. + """ + @spec put_annotations(t, input, Description.input() | nil) :: t + def put_annotations(graph, statements, annotations) + + def put_annotations(%__MODULE__{} = graph, %rdf_struct{} = statements, annotations) + when rdf_struct in [__MODULE__, Description] do + if annotations = normalize_annotations(annotations) do + Enum.reduce( + statements, + graph, + &%__MODULE__{ + &2 + | descriptions: + Map.put(&2.descriptions, &1, Description.change_subject(annotations, &1)) + } + ) + else + graph + end + end + + def put_annotations(graph, statements, annotations) do + put_annotations(graph, new(statements), annotations) + end + + @doc """ + Adds RDF-star annotations to the given set of statements overwriting all existing annotations with the given properties. + + The set of `statements` can be given in any input form (see `add/3`). + + The predicate-objects pairs to be added as annotations can be given as a tuple, + a list of tuples or a map. + """ + @spec put_annotation_properties(t, input, Description.input() | nil) :: t + def put_annotation_properties(graph, statements, annotations) + + def put_annotation_properties(%__MODULE__{} = graph, %rdf_struct{} = statements, annotations) + when rdf_struct in [__MODULE__, Description] do + if annotations = normalize_annotations(annotations) do + Enum.reduce( + statements, + graph, + &put_properties(&2, Description.change_subject(annotations, &1)) + ) + else + graph + end + end + + def put_annotation_properties(graph, statements, annotations) do + put_annotation_properties(graph, new(statements), annotations) + 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 """ Updates the description of the `subject` in `graph` with the given function. diff --git a/test/unit/star/graph_test.exs b/test/unit/star/graph_test.exs index eae9c5e..4fff87f 100644 --- a/test/unit/star/graph_test.exs +++ b/test/unit/star/graph_test.exs @@ -62,15 +62,15 @@ defmodule RDF.Star.Graph.Test do end end - describe "annotate option on add/3" do - test "with a predicate-object pair" do - assert Graph.add(graph(), statement(), annotate: {EX.AP, EX.AO}) == + describe "add/3 with add_annotations option" do + test "various statement forms annotated with a predicate-object pair" do + assert Graph.add(graph(), statement(), add_annotations: {EX.AP, EX.AO}) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP, EX.AO}) assert Graph.add(graph(), [{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}], - annotate: {EX.AP, EX.AO} + add_annotations: {EX.AP, EX.AO} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -85,35 +85,39 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP, EX.AO}) - assert Graph.add(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, annotate: {EX.AP, EX.AO}) == + assert Graph.add(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP, EX.AO}) == expected_graph - assert Graph.add(graph(), %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, annotate: {EX.AP, EX.AO}) == + assert Graph.add(graph(), %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + add_annotations: {EX.AP, EX.AO} + ) == expected_graph assert Graph.add(graph(), Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), - annotate: {EX.AP, EX.AO} + add_annotations: {EX.AP, EX.AO} ) == expected_graph end - test "with multiple annotations" do - assert Graph.add(graph(), statement(), annotate: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) == + test "annotations as a list of predicate-object pairs" do + assert Graph.add(graph(), statement(), add_annotations: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP1, EX.AO1}) |> Graph.add({statement(), EX.AP2, EX.AO2}) end - test "with a description graph" do - assert Graph.add(graph(), statement(), annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) == + test "annotations as a description graph" do + assert Graph.add(graph(), statement(), + add_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + ) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP1, EX.AO1}) |> Graph.add({statement(), EX.AP2, EX.AO2}) assert Graph.add(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, - annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + add_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -123,6 +127,195 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) end + + test "when annotations exist, they don't get overwritten" do + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO1}) + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO2}) == + graph() + |> Graph.add(statement()) + |> Graph.add({statement(), EX.AP, [EX.AO1, EX.AO2]}) + + expected_graph = + graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, [EX.AO1, EX.AO2]}) + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO1}) + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO2}) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO1}) + |> Graph.add(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + add_annotations: {EX.AP1, EX.AO2} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO1}) + |> Graph.add( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + add_annotations: {EX.AP1, EX.AO2} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + } + ) + |> Graph.add( + {EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + ) == + graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP3, EX.AO3}) + end + end + + test "add/3 with put_annotations option" do + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP1, EX.AO1}) + |> Graph.add(statement(), put_annotations: {EX.AP, EX.AO}) == + graph() + |> Graph.add(statement()) + |> Graph.add({statement(), EX.AP, EX.AO}) + + assert graph() + |> Graph.add_annotations(statement(), {EX.AP1, EX.AO1}) + |> Graph.add(statement(), put_annotations: {EX.AP, EX.AO}) == + graph() + |> Graph.add(statement()) + |> Graph.add({statement(), EX.AP, EX.AO}) + + expected_graph = + graph() + |> Graph.add({EX.S1, EX.P1, EX.O1}) + |> Graph.add({EX.S1, EX.P1, EX.O2}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO}) + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, put_annotations: {EX.AP1, EX.AO}) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.add(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, put_annotations: {EX.AP1, EX.AO}) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.add( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + put_annotations: {EX.AP1, EX.AO} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + } + ) + |> Graph.add( + {EX.S1, EX.P1, [EX.O1, EX.O2]}, + put_annotations: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + ) == + graph() + |> Graph.add({EX.S1, EX.P1, EX.O1}) + |> Graph.add({EX.S1, EX.P1, EX.O2}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO4}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO4}) + end + + test "add/3 with put_annotation_properties option" do + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP1, EX.AO1}) + |> Graph.add(statement(), put_annotation_properties: {EX.AP2, EX.AO2}) == + graph() + |> Graph.add(statement(), add_annotations: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) + + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO1}) + |> Graph.add(statement(), put_annotation_properties: {EX.AP, EX.AO2}) == + graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO2}) + + expected_graph = + graph() + |> Graph.add({EX.S1, EX.P1, EX.O1}) + |> Graph.add({EX.S1, EX.P1, EX.O2}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.add( + %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.add( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph end describe "put/3" do @@ -178,15 +371,68 @@ defmodule RDF.Star.Graph.Test do end end - describe "annotate option on put/3" do + test "put/3 with add_annotations option" do + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO1}) + |> Graph.put(statement(), add_annotations: {EX.AP, EX.AO2}) == + graph() + |> Graph.add(statement()) + |> Graph.add({statement(), EX.AP, [EX.AO1, EX.AO2]}) + + expected_graph = + graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, [EX.AO1, EX.AO2]}) + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO1}) + |> Graph.put({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO2}) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO1}) + |> Graph.put(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + add_annotations: {EX.AP1, EX.AO2} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, add_annotations: {EX.AP1, EX.AO1}) + |> Graph.put( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + add_annotations: {EX.AP1, EX.AO2} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + } + ) + |> Graph.put( + {EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + ) == + graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP3, EX.AO3}) + end + + describe "put/3 with put_annotations option" do test "with a predicate-object pair" do - assert Graph.put(graph(), statement(), annotate: {EX.AP, EX.AO}) == + assert Graph.put(graph(), statement(), put_annotations: {EX.AP, EX.AO}) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP, EX.AO}) assert Graph.put(graph(), [{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}], - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -201,20 +447,22 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP, EX.AO}) - assert Graph.put(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, annotate: {EX.AP, EX.AO}) == + assert Graph.put(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, put_annotations: {EX.AP, EX.AO}) == expected_graph - assert Graph.put(graph(), %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, annotate: {EX.AP, EX.AO}) == + assert Graph.put(graph(), %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + put_annotations: {EX.AP, EX.AO} + ) == expected_graph assert Graph.put(graph(), Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == expected_graph end test "with multiple annotations" do - assert Graph.put(graph(), statement(), annotate: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) == + assert Graph.put(graph(), statement(), put_annotations: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP1, EX.AO1}) @@ -222,14 +470,16 @@ defmodule RDF.Star.Graph.Test do end test "with a description graph" do - assert Graph.put(graph(), statement(), annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) == + assert Graph.put(graph(), statement(), + put_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + ) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP1, EX.AO1}) |> Graph.add({statement(), EX.AP2, EX.AO2}) assert Graph.put(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, - annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + put_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -242,7 +492,7 @@ defmodule RDF.Star.Graph.Test do test "with a RDF.Graph" do assert Graph.put(graph(), Graph.new({EX.S1, EX.P1, [EX.O1, EX.O2]}), - annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + put_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -255,8 +505,8 @@ defmodule RDF.Star.Graph.Test do test "when an annotation exists" do assert graph() - |> Graph.add(statement(), annotate: {EX.AP1, EX.AO1}) - |> Graph.put(statement(), annotate: {EX.AP, EX.AO}) == + |> Graph.add(statement(), add_annotations: {EX.AP1, EX.AO1}) + |> Graph.put(statement(), put_annotations: {EX.AP, EX.AO}) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP, EX.AO}) @@ -272,26 +522,26 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP, EX.AO}) assert graph() - |> Graph.add(base_graph, annotate: {EX.AP, EX.AO1}) - |> Graph.put({EX.S1, EX.P1, [EX.O1, EX.O2]}, annotate: {EX.AP, EX.AO}) == + |> Graph.add(base_graph, add_annotations: {EX.AP, EX.AO1}) + |> Graph.put({EX.S1, EX.P1, [EX.O1, EX.O2]}, put_annotations: {EX.AP, EX.AO}) == expected_graph assert graph() - |> Graph.add(base_graph, annotate: {EX.AP1, EX.AO}) - |> Graph.put(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, annotate: {EX.AP, EX.AO}) == + |> Graph.add(base_graph, add_annotations: {EX.AP1, EX.AO}) + |> Graph.put(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, put_annotations: {EX.AP, EX.AO}) == expected_graph assert graph() - |> Graph.add(base_graph, annotate: {EX.AP1, EX.AO1}) + |> Graph.add(base_graph, add_annotations: {EX.AP1, EX.AO1}) |> Graph.put(Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == expected_graph assert graph() - |> Graph.add(base_graph, annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) + |> Graph.add(base_graph, add_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) |> Graph.put({EX.S1, EX.P1, [EX.O1, EX.O2]}, - annotate: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + put_annotations: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -303,6 +553,67 @@ defmodule RDF.Star.Graph.Test do end end + test "put/3 with put_annotation_properties option" do + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP1, EX.AO1}) + |> Graph.put(statement(), put_annotation_properties: {EX.AP2, EX.AO2}) == + graph() + |> Graph.add(statement(), add_annotations: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) + + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO1}) + |> Graph.put(statement(), put_annotation_properties: {EX.AP, EX.AO2}) == + graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO2}) + + expected_graph = + graph() + |> Graph.add({EX.S1, EX.P1, EX.O1}) + |> Graph.add({EX.S1, EX.P1, EX.O2}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.put({EX.S1, EX.P1, [EX.O1, EX.O2]}, + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.put( + %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.put( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + end + test "put_properties/3" do graph = graph() @@ -321,15 +632,37 @@ defmodule RDF.Star.Graph.Test do assert graph_includes_statement?(graph, {statement(), EX.ap(), EX.ao2()}) end - describe "annotate option on put_properties/3" do - test "with a predicate-object pair" do - assert Graph.put_properties(graph(), statement(), annotate: {EX.AP, EX.AO}) == + test "put_properties/3 with add_annotations option" do + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + } + ) + |> Graph.put_properties( + {EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + ) == + graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP3, EX.AO3}) + end + + describe "put_properties/3 with put_annotations option" do + test "various statement forms annotated with a predicate-object pair" do + assert Graph.put_properties(graph(), statement(), put_annotations: {EX.AP, EX.AO}) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP, EX.AO}) assert Graph.put_properties(graph(), [{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}], - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -345,26 +678,26 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP, EX.AO}) assert Graph.put_properties(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == expected_graph assert Graph.put_properties(graph(), %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == expected_graph assert Graph.put_properties( graph(), Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == expected_graph end - test "with multiple annotations" do + test "annotations as a list of predicate-object pairs" do assert Graph.put_properties(graph(), statement(), - annotate: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}] + put_annotations: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}] ) == graph() |> Graph.add(statement()) @@ -372,9 +705,9 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({statement(), EX.AP2, EX.AO2}) end - test "with a description graph" do + test "annotations as a description graph" do assert Graph.put_properties(graph(), statement(), - annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + put_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} ) == graph() |> Graph.add(statement()) @@ -382,7 +715,7 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({statement(), EX.AP2, EX.AO2}) assert Graph.put_properties(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, - annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + put_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -393,9 +726,9 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) end - test "with a RDF.Graph" do + test "annotations as a RDF.Graph" do assert Graph.put_properties(graph(), Graph.new({EX.S1, EX.P1, [EX.O1, EX.O2]}), - annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} + put_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O1}) @@ -406,17 +739,17 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) end - test "when an annotation exists" do + test "when annotations exist, they get overwritten" do assert graph() - |> Graph.add(statement(), annotate: {EX.AP1, EX.AO1}) - |> Graph.put_properties(statement(), annotate: {EX.AP, EX.AO}) == + |> Graph.add(statement(), add_annotations: {EX.AP1, EX.AO1}) + |> Graph.put_properties(statement(), put_annotations: {EX.AP, EX.AO}) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP, EX.AO}) assert graph() - |> Graph.add(statement(), annotate: {EX.AP, EX.AO1}) - |> Graph.put_properties(statement(), annotate: {EX.AP, EX.AO2}) == + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO1}) + |> Graph.put_properties(statement(), put_annotations: {EX.AP, EX.AO2}) == graph() |> Graph.add(statement()) |> Graph.add({statement(), EX.AP, EX.AO2}) @@ -427,17 +760,17 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({EX.S1, EX.P2, EX.O2}) assert graph() - |> Graph.add(base_graph, annotate: {EX.AP, EX.AO1}) - |> Graph.put_properties({EX.S1, EX.P1, EX.O1}, annotate: {EX.AP, EX.AO}) - |> Graph.put_properties({EX.S1, EX.P2, EX.O2}, annotate: {EX.AP, EX.AO}) == + |> Graph.add(base_graph, add_annotations: {EX.AP, EX.AO1}) + |> Graph.put_properties({EX.S1, EX.P1, EX.O1}, put_annotations: {EX.AP, EX.AO}) + |> Graph.put_properties({EX.S1, EX.P2, EX.O2}, put_annotations: {EX.AP, EX.AO}) == base_graph |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) |> Graph.add({{EX.S1, EX.P2, EX.O2}, EX.AP, EX.AO}) assert graph() - |> Graph.add(base_graph, annotate: {EX.AP1, EX.AO}) + |> Graph.add(base_graph, add_annotations: {EX.AP1, EX.AO}) |> Graph.put_properties(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == base_graph |> Graph.add({EX.S1, EX.P1, EX.O2}) @@ -446,9 +779,9 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P2, EX.O2}, EX.AP1, EX.AO}) assert graph() - |> Graph.add(base_graph, annotate: {EX.AP1, EX.AO1}) + |> Graph.add(base_graph, add_annotations: {EX.AP1, EX.AO1}) |> Graph.put_properties(Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), - annotate: {EX.AP, EX.AO} + put_annotations: {EX.AP, EX.AO} ) == base_graph |> Graph.add({EX.S1, EX.P1, EX.O2}) @@ -457,9 +790,9 @@ defmodule RDF.Star.Graph.Test do |> Graph.add({{EX.S1, EX.P2, EX.O2}, EX.AP1, EX.AO1}) assert graph() - |> Graph.add(base_graph, annotate: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) + |> Graph.add(base_graph, add_annotations: %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) |> Graph.put_properties({EX.S1, EX.P1, EX.O2}, - annotate: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + put_annotations: %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} ) == graph() |> Graph.add({EX.S1, EX.P1, EX.O2}) @@ -473,29 +806,590 @@ defmodule RDF.Star.Graph.Test do end end + test "put_properties/3 with put_annotation_properties option" do + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP1, EX.AO1}) + |> Graph.put_properties(statement(), put_annotation_properties: {EX.AP2, EX.AO2}) == + graph() + |> Graph.add(statement(), add_annotations: [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) + + assert graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO1}) + |> Graph.put_properties(statement(), put_annotation_properties: %{EX.AP => EX.AO2}) == + graph() + |> Graph.add(statement(), add_annotations: {EX.AP, EX.AO2}) + + expected_graph = + graph() + |> Graph.add({EX.S1, EX.P1, EX.O1}) + |> Graph.add({EX.S1, EX.P1, EX.O2}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.put_properties({EX.S1, EX.P1, [EX.O1, EX.O2]}, + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.put_properties( + %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + + assert graph() + |> Graph.add({EX.S1, EX.P1, [EX.O1, EX.O2]}, + add_annotations: [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ] + ) + |> Graph.put_properties( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + put_annotation_properties: {EX.AP1, EX.AO1} + ) == + expected_graph + end + + test "delete/3" do + assert graph_with_annotation() |> Graph.delete(star_statement()) == graph() + end + + describe "delete/3 with delete_annotations option" do + test "with false, no annotations are deleted (default)" do + assert graph() + |> Graph.add(statement(), add_annotations: {EX.p(), EX.O}) + |> Graph.delete(statement(), delete_annotations: false) == + graph() |> Graph.add({statement(), EX.p(), EX.O}) + + assert graph() + |> Graph.add(statement(), add_annotations: {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(), add_annotations: {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}}, + add_annotations: %{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_descriptions/3 with delete_annotations option" do + test "with false, no annotations are deleted (default)" do + assert graph() + |> Graph.add(statement(), add_annotations: {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(), add_annotations: {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(), add_annotations: {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 + + describe "add_annotations/3" do + test "various statement forms annotated with a predicate-object pair" do + assert Graph.add_annotations(graph(), statement(), {EX.AP, EX.AO}) == + graph() + |> Graph.add({statement(), EX.AP, EX.AO}) + + expected_graph = + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP, EX.AO}) + + assert Graph.add_annotations(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP, EX.AO}) == + expected_graph + + assert Graph.add_annotations( + graph(), + %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + {EX.AP, EX.AO} + ) == + expected_graph + + assert Graph.add_annotations( + graph(), + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + {EX.AP, EX.AO} + ) == + expected_graph + + assert Graph.add_annotations( + graph(), + Graph.new(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}), + {EX.AP, EX.AO} + ) == + expected_graph + end + + test "annotations as a list of predicate-object pairs" do + assert Graph.add_annotations(graph(), statement(), [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) == + graph() + |> Graph.add({statement(), EX.AP1, EX.AO1}) + |> Graph.add({statement(), EX.AP2, EX.AO2}) + end + + test "annotations as a description graph" do + assert Graph.add_annotations(graph(), statement(), %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) == + graph() + |> Graph.add({statement(), EX.AP1, EX.AO1}) + |> Graph.add({statement(), EX.AP2, EX.AO2}) + + assert Graph.add_annotations(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + end + + test "annotations as a RDF.Graph" do + assert Graph.add_annotations(graph(), Graph.new({EX.S1, EX.P1, [EX.O1, EX.O2]}), %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + end + + test "when annotations exist, they don't get overwritten" do + assert graph() + |> Graph.add_annotations(statement(), {EX.AP, EX.AO1}) + |> Graph.add_annotations(statement(), {EX.AP, EX.AO2}) == + graph() + |> Graph.add({statement(), EX.AP, [EX.AO1, EX.AO2]}) + + expected_graph = + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, [EX.AO1, EX.AO2]}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, [EX.AO1, EX.AO2]}) + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP1, EX.AO1}) + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP1, EX.AO2}) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP1, EX.AO1}) + |> Graph.add_annotations(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, {EX.AP1, EX.AO2}) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP1, EX.AO1}) + |> Graph.add_annotations( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + {EX.AP1, EX.AO2} + ) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) + |> Graph.add_annotations( + {EX.S1, EX.P1, [EX.O1, EX.O2]}, + %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + ) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, [EX.AO2, EX.AO4]}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP3, EX.AO3}) + end + end + + describe "put_annotations/3" do + test "various statement forms annotated with a predicate-object pair" do + assert Graph.put_annotations(graph(), statement(), {EX.AP, EX.AO}) == + graph() + |> Graph.add({statement(), EX.AP, EX.AO}) + + assert Graph.put_annotations( + graph(), + [{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}], + {EX.AP, EX.AO} + ) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) + |> Graph.add({{EX.S2, EX.P2, EX.O2}, EX.AP, EX.AO}) + + expected_graph = + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP, EX.AO}) + + assert Graph.put_annotations(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP, EX.AO}) == + expected_graph + + assert Graph.put_annotations( + graph(), + %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + {EX.AP, EX.AO} + ) == + expected_graph + + assert Graph.put_annotations( + graph(), + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + {EX.AP, EX.AO} + ) == + expected_graph + end + + test "annotations as a list of predicate-object pairs" do + assert Graph.put_annotations(graph(), statement(), [{EX.AP1, EX.AO1}, {EX.AP2, EX.AO2}]) == + graph() + |> Graph.add({statement(), EX.AP1, EX.AO1}) + |> Graph.add({statement(), EX.AP2, EX.AO2}) + end + + test "annotations as a description graph" do + assert Graph.put_annotations(graph(), statement(), %{EX.AP1 => EX.AO1, EX.AP2 => EX.AO2}) == + graph() + |> Graph.add({statement(), EX.AP1, EX.AO1}) + |> Graph.add({statement(), EX.AP2, EX.AO2}) + + assert Graph.put_annotations(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + end + + test "annotations as a RDF.Graph" do + assert Graph.put_annotations(graph(), Graph.new({EX.S1, EX.P1, [EX.O1, EX.O2]}), %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + end + + test "when annotations exist, they get overwritten" do + assert graph() + |> Graph.add_annotations(statement(), {EX.AP1, EX.AO1}) + |> Graph.put_annotations(statement(), {EX.AP, EX.AO}) == + graph() + |> Graph.add({statement(), EX.AP, EX.AO}) + + expected_graph = + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO}) + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ]) + |> Graph.put_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP1, EX.AO}) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ]) + |> Graph.put_annotations(%{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, {EX.AP1, EX.AO}) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ]) + |> Graph.put_annotations( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + {EX.AP1, EX.AO} + ) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) + |> Graph.put_annotations( + {EX.S1, EX.P1, [EX.O1, EX.O2]}, + %{EX.AP3 => EX.AO3, EX.AP2 => EX.AO4} + ) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP3, EX.AO3}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO4}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO4}) + end + end + + describe "put_annotation_properties/3" do + test "various statement forms annotated with a predicate-object pair" do + assert Graph.put_annotation_properties(graph(), statement(), {EX.AP, EX.AO}) == + graph() + |> Graph.add({statement(), EX.AP, EX.AO}) + + assert Graph.put_annotation_properties( + graph(), + [{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}], + {EX.AP, EX.AO} + ) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) + |> Graph.add({{EX.S2, EX.P2, EX.O2}, EX.AP, EX.AO}) + + expected_graph = + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP, EX.AO}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP, EX.AO}) + + assert Graph.put_annotation_properties( + graph(), + {EX.S1, EX.P1, [EX.O1, EX.O2]}, + {EX.AP, EX.AO} + ) == + expected_graph + + assert Graph.put_annotation_properties( + graph(), + %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + {EX.AP, EX.AO} + ) == + expected_graph + + assert Graph.put_annotation_properties( + graph(), + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + {EX.AP, EX.AO} + ) == + expected_graph + end + + test "annotations as a list of predicate-object pairs" do + assert Graph.put_annotation_properties(graph(), statement(), [ + {EX.AP1, EX.AO1}, + {EX.AP2, EX.AO2} + ]) == + graph() + |> Graph.add({statement(), EX.AP1, EX.AO1}) + |> Graph.add({statement(), EX.AP2, EX.AO2}) + end + + test "annotations as a description graph" do + assert Graph.put_annotation_properties(graph(), statement(), %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) == + graph() + |> Graph.add({statement(), EX.AP1, EX.AO1}) + |> Graph.add({statement(), EX.AP2, EX.AO2}) + + assert Graph.put_annotation_properties(graph(), {EX.S1, EX.P1, [EX.O1, EX.O2]}, %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + }) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + end + + test "annotations as a RDF.Graph" do + assert Graph.put_annotation_properties( + graph(), + Graph.new({EX.S1, EX.P1, [EX.O1, EX.O2]}), + %{ + EX.AP1 => EX.AO1, + EX.AP2 => EX.AO2 + } + ) == + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + end + + test "when annotations exist, only the given properties get overwritten" do + assert graph() + |> Graph.add_annotations(statement(), {EX.AP1, EX.AO1}) + |> Graph.put_annotation_properties(statement(), {EX.AP2, EX.AO2}) == + graph() + |> Graph.add({statement(), EX.AP1, EX.AO1}) + |> Graph.add({statement(), EX.AP2, EX.AO2}) + + assert graph() + |> Graph.add_annotations(statement(), {EX.AP, EX.AO1}) + |> Graph.put_annotation_properties(statement(), {EX.AP, EX.AO2}) == + graph() + |> Graph.add({statement(), EX.AP, EX.AO2}) + + expected_graph = + graph() + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP1, EX.AO1}) + |> Graph.add({{EX.S1, EX.P1, EX.O1}, EX.AP2, EX.AO2}) + |> Graph.add({{EX.S1, EX.P1, EX.O2}, EX.AP2, EX.AO2}) + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ]) + |> Graph.put_annotation_properties({EX.S1, EX.P1, [EX.O1, EX.O2]}, {EX.AP1, EX.AO1}) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ]) + |> Graph.put_annotation_properties( + %{EX.S1 => %{EX.P1 => [EX.O1, EX.O2]}}, + {EX.AP1, EX.AO1} + ) == + expected_graph + + assert graph() + |> Graph.add_annotations({EX.S1, EX.P1, [EX.O1, EX.O2]}, [ + {EX.AP1, EX.AO}, + {EX.AP2, EX.AO2} + ]) + |> Graph.put_annotation_properties( + Description.new(EX.S1, init: %{EX.P1 => [EX.O1, EX.O2]}), + {EX.AP1, EX.AO1} + ) == + expected_graph + 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}) + graph = Graph.add(graph(), statement(), add_annotations: {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.add(statement(), add_annotations: {EX.p(), EX.O}) |> Graph.delete_annotations(statement(), true) == graph() |> Graph.add(statement()) assert graph() - |> Graph.add(statement(), annotate: {EX.p(), EX.O}) + |> Graph.add(statement(), add_annotations: {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.add(statement(), add_annotations: [{EX.p1(), EX.O1}, {EX.p2(), EX.O2}]) |> Graph.delete_annotations(statement(), EX.p2()) == - Graph.add(graph(), statement(), annotate: {EX.p1(), EX.O1}) + Graph.add(graph(), statement(), add_annotations: {EX.p1(), EX.O1}) graph = graph() @@ -542,114 +1436,6 @@ defmodule RDF.Star.Graph.Test do end end - test "delete/3" do - assert graph_with_annotation() |> Graph.delete(star_statement()) == graph() - end - - 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()