From 731b168ef49db358eb65dc275b98fde002feede9 Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Thu, 4 Apr 2019 01:55:34 +0200 Subject: [PATCH] Add RDF.Data.equal?/2 --- CHANGELOG.md | 3 +- lib/rdf/data.ex | 89 +++++++++++++++++++++++++++++++++++++++++ test/unit/data_test.exs | 45 +++++++++++++++++++++ 3 files changed, 136 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9f2e140..8f5cedb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and - the structure now has a `prefixes` field with an optional `RDF.PrefixMap` - new functions `add_prefixes/2`, `delete_prefixes/2` and `clear_prefixes/1` - configurable `RDF.default_prefixes` -- `RDF.Description.equal?/2`, `RDF.Graph.equal?/2` and `RDF.Dataset.equal?/2` +- `RDF.Description.equal?/2`, `RDF.Graph.equal?/2`, `RDF.Dataset.equal?/2` and + `RDF.Data.equal?/2` ### Changed diff --git a/lib/rdf/data.ex b/lib/rdf/data.ex index edefa65b..59f78332 100644 --- a/lib/rdf/data.ex +++ b/lib/rdf/data.ex @@ -101,6 +101,26 @@ defprotocol RDF.Data do Returns a nested map of the native Elixir values of a RDF data structure with values mapped with the given function. """ def values(data, mapping) + + @doc """ + Checks if two RDF data structures are equal. + + Two RDF data structures are considered to be equal if they contain the same triples. + + - comparing two `RDF.Description`s it's just the same as `RDF.Description.equal?/2` + - comparing two `RDF.Graph`s differs in `RDF.Graph.equal?/2` in that the graph + name is ignored + - comparing two `RDF.Dataset`s differs in `RDF.Dataset.equal?/2` in that the + dataset name is ignored + - a `RDF.Description` is equal to a `RDF.Graph`, if the graph has just one + description which equals the given description + - a `RDF.Description` is equal to a `RDF.Dataset`, if the dataset has just one + graph which contains only the given description + - a `RDF.Graph` is equal to a `RDF.Dataset`, if the dataset has just one + graph which equals the given graph; note that in this case the graph names + must match + """ + def equal?(data1, data2) end defimpl RDF.Data, for: RDF.Description do @@ -169,6 +189,24 @@ defimpl RDF.Data, for: RDF.Description do def statement_count(description), do: RDF.Description.count(description) def values(description), do: RDF.Description.values(description) def values(description, mapping), do: RDF.Description.values(description, mapping) + + def equal?(description, %RDF.Description{} = other_description) do + RDF.Description.equal?(description, other_description) + end + + def equal?(description, %RDF.Graph{} = graph) do + with [single_description] <- RDF.Graph.descriptions(graph) do + RDF.Description.equal?(description, single_description) + else + _ -> false + end + end + + def equal?(description, %RDF.Dataset{} = dataset) do + RDF.Data.equal?(dataset, description) + end + + def equal?(_, _), do: false end @@ -231,6 +269,18 @@ defimpl RDF.Data, for: RDF.Graph do def statement_count(graph), do: RDF.Graph.triple_count(graph) def values(graph), do: RDF.Graph.values(graph) def values(graph, mapping), do: RDF.Graph.values(graph, mapping) + + def equal?(graph, %RDF.Description{} = description), + do: RDF.Data.equal?(description, graph) + + def equal?(graph, %RDF.Graph{} = other_graph), + do: RDF.Graph.equal?(RDF.Data.Utils.normalize_graph(graph), + RDF.Data.Utils.normalize_graph(other_graph)) + + def equal?(graph, %RDF.Dataset{} = dataset), + do: RDF.Data.equal?(dataset, graph) + + def equal?(_, _), do: false end @@ -286,4 +336,43 @@ defimpl RDF.Data, for: RDF.Dataset do def statement_count(dataset), do: RDF.Dataset.statement_count(dataset) def values(dataset), do: RDF.Dataset.values(dataset) def values(dataset, mapping), do: RDF.Dataset.values(dataset, mapping) + + def equal?(dataset, %RDF.Description{} = description) do + with [graph] <- RDF.Dataset.graphs(dataset) do + RDF.Data.equal?(description, graph) + else + _ -> false + end + end + + def equal?(dataset, %RDF.Graph{} = graph) do + with [single_graph] <- RDF.Dataset.graphs(dataset) do + RDF.Graph.equal?(graph, single_graph) + else + _ -> false + end + end + + def equal?(dataset, %RDF.Dataset{} = other_dataset) do + RDF.Dataset.equal?(RDF.Data.Utils.normalize_dataset(dataset), + RDF.Data.Utils.normalize_dataset(other_dataset)) + end + + def equal?(_, _), do: false +end + +defmodule RDF.Data.Utils do + @moduledoc false + + def normalize_graph(graph) do + %RDF.Graph{graph | name: nil} + end + + def normalize_dataset(%RDF.Dataset{graphs: graphs}) do + %RDF.Dataset{name: nil, graphs: + Map.new(graphs, fn {name, graph} -> + {name, RDF.Graph.clear_prefixes(graph)} + end) + } + end end diff --git a/test/unit/data_test.exs b/test/unit/data_test.exs index 7b750c95..18e68f37 100644 --- a/test/unit/data_test.exs +++ b/test/unit/data_test.exs @@ -153,6 +153,17 @@ defmodule RDF.DataTest do RDF.Term.value(EX.p3) => ["_:foo", "bar"], } end + + test "equal/2", %{description: description, graph: graph, dataset: dataset} do + assert RDF.Data.equal?(description, description) + assert RDF.Data.equal?(description, Graph.new(description)) + assert RDF.Data.equal?(description, Graph.new(description, name: EX.Graph)) + assert RDF.Data.equal?(description, Dataset.new(description)) + + refute RDF.Data.equal?(description, description |> EX.p4(EX.O4)) + refute RDF.Data.equal?(description, graph) + refute RDF.Data.equal?(description, dataset) + end end @@ -304,6 +315,19 @@ defmodule RDF.DataTest do }, } end + + test "equal/2", %{graph: graph, description: description, dataset: dataset} do + assert RDF.Data.equal?(graph, graph) + assert RDF.Data.equal?(graph, RDF.Graph.new(graph, name: EX.Graph)) + assert RDF.Data.equal?(Graph.new(description), description) + assert RDF.Data.equal?(Graph.new(description, name: EX.Graph), description) + assert RDF.Data.equal?(graph, Dataset.new(graph)) + + refute RDF.Data.equal?(graph, graph |> Graph.delete_subjects(EX.S2)) + refute RDF.Data.equal?(graph |> Graph.delete_subjects(EX.S2), graph) + refute RDF.Data.equal?(graph, description) + refute RDF.Data.equal?(graph, dataset) + end end @@ -505,6 +529,27 @@ defmodule RDF.DataTest do } } end + + test "equal/2", %{graph: graph, description: description, dataset: dataset} do + assert RDF.Data.equal?(dataset, dataset) + assert RDF.Data.equal?(dataset, Dataset.new(dataset, name: EX.Dataset)) + assert RDF.Data.equal?(Dataset.new(description), description) + assert RDF.Data.equal?(Dataset.new(graph), graph) + assert RDF.Data.equal?(Dataset.new(graph), RDF.Graph.add_prefixes(graph, %{ex: EX})) + assert RDF.Data.equal?((Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph1, prefixes: %{ex: EX}))), + (Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph1, prefixes: %{ex: RDF})))) + + refute RDF.Data.equal?(dataset, dataset |> Dataset.delete_graph(EX.NamedGraph)) + refute RDF.Data.equal?(dataset |> Dataset.delete_graph(EX.NamedGraph), dataset) + refute RDF.Data.equal?((Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph1))), + (Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph2)))) + refute RDF.Data.equal?(dataset, description) + refute RDF.Data.equal?(dataset, graph) + end end end