rdf-ex/lib/rdf/data.ex

406 lines
12 KiB
Elixir
Raw Normal View History

2017-05-24 21:37:09 +00:00
defprotocol RDF.Data do
@moduledoc """
An abstraction over the different data structures for collections of RDF statements.
"""
@type t :: RDF.Description.t() | RDF.Graph.t() | RDF.Dataset.t()
2017-06-08 19:50:46 +00:00
@doc """
Adds statements to a RDF data structure.
As opposed to the specific `add` functions on the RDF data structures, which
always return the same structure type than the first argument, `merge` might
result in another RDF data structure, eg. merging two `RDF.Description` with
different subjects results in a `RDF.Graph` or adding a quad to a `RDF.Graph`
with a different name than the graph context of the quad results in a
`RDF.Dataset`. But it is always guaranteed that the resulting structure has
a `RDF.Data` implementation.
"""
def merge(data, input, opts \\ [])
2017-06-08 19:50:46 +00:00
2017-05-24 21:37:09 +00:00
@doc """
Deletes statements from a RDF data structure.
2017-06-08 19:50:46 +00:00
As opposed to the `delete` functions on RDF data structures directly, this
function only deletes exactly matching structures.
2017-05-24 21:37:09 +00:00
"""
def delete(data, input, opts \\ [])
2017-05-24 21:37:09 +00:00
@doc """
Deletes one statement from a RDF data structure and returns a tuple with deleted statement and the changed data structure.
"""
def pop(data)
@doc """
Checks if the given statement exists within a RDF data structure.
"""
def include?(data, input, opts \\ [])
2017-05-24 21:37:09 +00:00
@doc """
Checks if a RDF data structure contains statements about the given resource.
2017-05-24 21:37:09 +00:00
"""
def describes?(data, subject)
2017-05-24 21:37:09 +00:00
2017-06-05 00:48:39 +00:00
@doc """
Returns a `RDF.Description` of the given subject.
Note: On a `RDF.Dataset` this will return an aggregated `RDF.Description` with
the statements about this subject from all graphs.
"""
def description(data, subject)
2017-07-07 17:03:01 +00:00
@doc """
Returns all `RDF.Description`s within a RDF data structure.
Note: On a `RDF.Dataset` this will return aggregated `RDF.Description`s about
the same subject from all graphs.
"""
def descriptions(data)
@doc """
Returns the list of all statements of a RDF data structure.
"""
def statements(data)
2017-05-24 21:37:09 +00:00
@doc """
Returns the set of all resources which are subject of the statements of a RDF data structure.
"""
def subjects(data)
@doc """
Returns the set of all properties used within the statements of RDF data structure.
"""
def predicates(data)
@doc """
Returns the set of all resources used in the objects within the statements of a RDF data structure.
"""
def objects(data)
@doc """
Returns the set of all resources used within the statements of a RDF data structure
"""
def resources(data)
@doc """
Returns the count of all resources which are subject of the statements of a RDF data structure.
"""
def subject_count(data)
@doc """
Returns the count of all statements of a RDF data structure.
"""
def statement_count(data)
2018-10-28 02:50:48 +00:00
@doc """
Returns a nested map of the native Elixir values of a RDF data structure.
When a `:context` option is given with a `RDF.PropertyMap`, predicates will
be mapped to the terms defined in the `RDF.PropertyMap`, if present.
2018-10-28 02:50:48 +00:00
"""
def values(data, opts \\ [])
2018-10-28 02:50:48 +00:00
@doc """
Returns a map representation of a RDF data structure where each element from its statements is mapped with the given function.
"""
def map(data, fun)
2019-04-03 23:55:34 +00:00
@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)
2017-05-24 21:37:09 +00:00
end
2017-06-04 02:20:08 +00:00
defimpl RDF.Data, for: RDF.Description do
2020-10-10 20:23:01 +00:00
alias RDF.{Description, Graph, Dataset, Statement}
def merge(description, input, opts \\ [])
2020-10-10 20:23:01 +00:00
def merge(%Description{subject: subject} = description, {s, _, _} = triple, opts) do
with ^subject <- Statement.coerce_subject(s) do
Description.add(description, triple, opts)
2017-06-08 19:50:46 +00:00
else
_ ->
2020-10-10 20:23:01 +00:00
Graph.new(description)
|> Graph.add(triple, opts)
2017-06-08 19:50:46 +00:00
end
end
def merge(description, {_, _, _, _} = quad, opts),
2020-10-10 20:23:01 +00:00
do: Dataset.new(description) |> Dataset.add(quad, opts)
2017-06-08 19:50:46 +00:00
2020-06-29 08:37:42 +00:00
def merge(
2020-10-10 20:23:01 +00:00
%Description{subject: subject} = description,
%Description{subject: other_subject} = other_description,
opts
2020-06-29 08:37:42 +00:00
)
when other_subject == subject,
2020-10-10 20:23:01 +00:00
do: Description.add(description, other_description, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def merge(description, %Description{} = other_description, opts),
do: Graph.new(description) |> Graph.add(other_description, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def merge(description, %Graph{} = graph, opts),
do: RDF.Data.merge(graph, description, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def merge(description, %Dataset{} = dataset, opts),
do: RDF.Data.merge(dataset, description, opts)
def delete(description, input, opts \\ [])
2017-06-08 19:50:46 +00:00
2020-06-29 08:37:42 +00:00
def delete(
2020-10-10 20:23:01 +00:00
%Description{subject: subject} = description,
%Description{subject: other_subject},
_opts
2020-06-29 08:37:42 +00:00
)
when subject != other_subject,
do: description
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def delete(description, input, opts), do: Description.delete(description, input, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def pop(description), do: Description.pop(description)
2017-06-04 02:20:08 +00:00
def include?(description, input, opts \\ []),
2020-10-10 20:23:01 +00:00
do: Description.include?(description, input, opts)
2017-06-04 02:20:08 +00:00
def describes?(description, subject),
2020-10-10 20:23:01 +00:00
do: Description.describes?(description, subject)
2017-06-05 00:48:39 +00:00
2020-10-10 20:23:01 +00:00
def description(%Description{subject: subject} = description, s) do
with ^subject <- Statement.coerce_subject(s) do
2017-06-05 00:48:39 +00:00
description
else
2020-10-10 20:23:01 +00:00
_ -> Description.new(s)
2017-06-05 00:48:39 +00:00
end
end
2017-07-07 17:03:01 +00:00
def descriptions(description), do: [description]
2020-10-10 20:23:01 +00:00
def statements(description), do: Description.statements(description)
2020-10-10 20:23:01 +00:00
def subjects(%Description{subject: subject}), do: MapSet.new([subject])
def predicates(description), do: Description.predicates(description)
def objects(description), do: Description.objects(description)
2017-06-04 02:20:08 +00:00
2020-10-10 20:23:01 +00:00
def resources(%Description{subject: subject} = description),
do: Description.resources(description) |> MapSet.put(subject)
2017-06-04 02:20:08 +00:00
2020-06-29 08:37:42 +00:00
def subject_count(_), do: 1
2020-10-10 20:23:01 +00:00
def statement_count(description), do: Description.count(description)
def values(description, opts \\ []),
do: Description.values(description, opts)
2020-10-10 20:23:01 +00:00
def map(description, fun), do: Description.map(description, fun)
2019-04-03 23:55:34 +00:00
2020-10-10 20:23:01 +00:00
def equal?(description, %Description{} = other_description) do
Description.equal?(description, other_description)
2019-04-03 23:55:34 +00:00
end
2020-10-10 20:23:01 +00:00
def equal?(description, %Graph{} = graph) do
with [single_description] <- Graph.descriptions(graph) do
Description.equal?(description, single_description)
2019-04-03 23:55:34 +00:00
else
_ -> false
end
end
2020-10-10 20:23:01 +00:00
def equal?(description, %Dataset{} = dataset) do
2019-04-03 23:55:34 +00:00
RDF.Data.equal?(dataset, description)
end
def equal?(_, _), do: false
2017-06-04 02:20:08 +00:00
end
defimpl RDF.Data, for: RDF.Graph do
2020-10-10 20:23:01 +00:00
alias RDF.{Description, Graph, Dataset, Statement}
def merge(graph, input, opts \\ [])
2020-10-10 20:23:01 +00:00
def merge(%Graph{name: name} = graph, {_, _, _, graph_context} = quad, opts) do
with ^name <- Statement.coerce_graph_name(graph_context) do
Graph.add(graph, quad, opts)
2017-06-08 19:50:46 +00:00
else
_ ->
2020-10-10 20:23:01 +00:00
Dataset.new(graph)
|> Dataset.add(quad, opts)
2017-06-08 19:50:46 +00:00
end
end
def merge(graph, {_, _, _} = triple, opts),
2020-10-10 20:23:01 +00:00
do: Graph.add(graph, triple, opts)
2017-06-08 19:50:46 +00:00
def merge(description, {_, _, _, _} = quad, opts),
2020-10-10 20:23:01 +00:00
do: Dataset.new(description) |> Dataset.add(quad, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def merge(graph, %Description{} = description, opts),
do: Graph.add(graph, description, opts)
2017-06-08 19:50:46 +00:00
2020-06-29 08:37:42 +00:00
def merge(
2020-10-10 20:23:01 +00:00
%Graph{name: name} = graph,
%Graph{name: other_name} = other_graph,
opts
2020-06-29 08:37:42 +00:00
)
when other_name == name,
2020-10-10 20:23:01 +00:00
do: Graph.add(graph, other_graph, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def merge(graph, %Graph{} = other_graph, opts),
do: Dataset.new(graph) |> Dataset.add(other_graph, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def merge(graph, %Dataset{} = dataset, opts),
do: RDF.Data.merge(dataset, graph, opts)
2017-06-08 19:50:46 +00:00
def delete(graph, input, opts \\ [])
2020-10-10 20:23:01 +00:00
def delete(%Graph{name: name} = graph, %Graph{name: other_name}, _opts)
2020-06-29 08:37:42 +00:00
when name != other_name,
do: graph
2020-10-10 20:23:01 +00:00
def delete(graph, input, opts), do: Graph.delete(graph, input, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def pop(graph), do: Graph.pop(graph)
2020-10-10 20:23:01 +00:00
def include?(graph, input, opts \\ []), do: Graph.include?(graph, input, opts)
def describes?(graph, subject),
2020-10-10 20:23:01 +00:00
do: Graph.describes?(graph, subject)
2017-06-05 00:48:39 +00:00
def description(graph, subject),
2020-10-10 20:23:01 +00:00
do: Graph.description(graph, subject) || Description.new(subject)
2017-06-05 00:48:39 +00:00
2020-10-10 20:23:01 +00:00
def descriptions(graph), do: Graph.descriptions(graph)
2017-07-07 17:03:01 +00:00
2020-10-10 20:23:01 +00:00
def statements(graph), do: Graph.statements(graph)
2020-10-10 20:23:01 +00:00
def subjects(graph), do: Graph.subjects(graph)
def predicates(graph), do: Graph.predicates(graph)
def objects(graph), do: Graph.objects(graph)
def resources(graph), do: Graph.resources(graph)
2020-10-10 20:23:01 +00:00
def subject_count(graph), do: Graph.subject_count(graph)
def statement_count(graph), do: Graph.triple_count(graph)
def values(graph, opts \\ []), do: Graph.values(graph, opts)
2020-10-10 20:23:01 +00:00
def map(graph, fun), do: Graph.map(graph, fun)
2019-04-03 23:55:34 +00:00
2020-10-10 20:23:01 +00:00
def equal?(graph, %Description{} = description),
2019-04-03 23:55:34 +00:00
do: RDF.Data.equal?(description, graph)
2020-10-10 20:23:01 +00:00
def equal?(graph, %Graph{} = other_graph),
2020-06-29 08:37:42 +00:00
do:
2020-10-10 20:23:01 +00:00
Graph.equal?(
%Graph{graph | name: nil},
%Graph{other_graph | name: nil}
2020-06-29 08:37:42 +00:00
)
2019-04-03 23:55:34 +00:00
2020-10-10 20:23:01 +00:00
def equal?(graph, %Dataset{} = dataset),
2019-04-03 23:55:34 +00:00
do: RDF.Data.equal?(dataset, graph)
def equal?(_, _), do: false
end
defimpl RDF.Data, for: RDF.Dataset do
2020-10-10 20:23:01 +00:00
alias RDF.{Description, Graph, Dataset, Statement}
def merge(dataset, input, opts \\ [])
def merge(dataset, {_, _, _} = triple, opts),
2020-10-10 20:23:01 +00:00
do: Dataset.add(dataset, triple, opts)
def merge(dataset, {_, _, _, _} = quad, opts),
2020-10-10 20:23:01 +00:00
do: Dataset.add(dataset, quad, opts)
2020-06-29 08:37:42 +00:00
2020-10-10 20:23:01 +00:00
def merge(dataset, %Description{} = description, opts),
do: Dataset.add(dataset, description, opts)
2020-06-29 08:37:42 +00:00
2020-10-10 20:23:01 +00:00
def merge(dataset, %Graph{} = graph, opts),
do: Dataset.add(dataset, graph, opts)
2020-06-29 08:37:42 +00:00
2020-10-10 20:23:01 +00:00
def merge(dataset, %Dataset{} = other_dataset, opts),
do: Dataset.add(dataset, other_dataset, opts)
2020-06-29 08:37:42 +00:00
def delete(dataset, input, opts \\ [])
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def delete(%Dataset{name: name} = dataset, %Dataset{name: other_name}, _opts)
2020-06-29 08:37:42 +00:00
when name != other_name,
do: dataset
2020-10-10 20:23:01 +00:00
def delete(dataset, input, opts), do: Dataset.delete(dataset, input, opts)
2017-06-08 19:50:46 +00:00
2020-10-10 20:23:01 +00:00
def pop(dataset), do: Dataset.pop(dataset)
2020-10-10 20:23:01 +00:00
def include?(dataset, input, opts), do: Dataset.include?(dataset, input, opts)
def describes?(dataset, subject),
2020-10-10 20:23:01 +00:00
do: Dataset.who_describes(dataset, subject) != []
2017-06-05 00:48:39 +00:00
def description(dataset, subject) do
2020-10-10 20:23:01 +00:00
subject = Statement.coerce_subject(subject)
Enum.reduce(Dataset.graphs(dataset), Description.new(subject), fn
%Graph{descriptions: %{^subject => graph_description}}, description ->
Description.add(description, graph_description)
_, description ->
description
end)
2017-06-05 00:48:39 +00:00
end
2017-07-07 17:03:01 +00:00
def descriptions(dataset) do
dataset
|> subjects
2020-06-29 08:37:42 +00:00
|> Enum.map(&description(dataset, &1))
2017-07-07 17:03:01 +00:00
end
2020-10-10 20:23:01 +00:00
def statements(dataset), do: Dataset.statements(dataset)
2020-10-10 20:23:01 +00:00
def subjects(dataset), do: Dataset.subjects(dataset)
def predicates(dataset), do: Dataset.predicates(dataset)
def objects(dataset), do: Dataset.objects(dataset)
def resources(dataset), do: Dataset.resources(dataset)
2020-06-29 08:37:42 +00:00
def subject_count(dataset), do: dataset |> subjects |> Enum.count()
2020-10-10 20:23:01 +00:00
def statement_count(dataset), do: Dataset.statement_count(dataset)
def values(dataset, opts \\ []), do: Dataset.values(dataset, opts)
2020-10-10 20:23:01 +00:00
def map(dataset, fun), do: Dataset.map(dataset, fun)
2019-04-03 23:55:34 +00:00
2020-10-10 20:23:01 +00:00
def equal?(dataset, %Description{} = description) do
with [graph] <- Dataset.graphs(dataset) do
2019-04-03 23:55:34 +00:00
RDF.Data.equal?(description, graph)
else
_ -> false
end
end
2020-10-10 20:23:01 +00:00
def equal?(dataset, %Graph{} = graph) do
with [single_graph] <- Dataset.graphs(dataset) do
Graph.equal?(graph, single_graph)
2019-04-03 23:55:34 +00:00
else
_ -> false
end
end
2020-10-10 20:23:01 +00:00
def equal?(dataset, %Dataset{} = other_dataset) do
Dataset.equal?(
%Dataset{dataset | name: nil},
%Dataset{other_dataset | name: nil}
2020-06-29 08:37:42 +00:00
)
2019-04-03 23:55:34 +00:00
end
def equal?(_, _), do: false
end