Add describes?/1 to RDF.Data protocol and all RDF data structures

This commit is contained in:
Marcel Otto 2017-07-23 23:59:50 +02:00
parent a6db9723ca
commit dc7dce7dbc
6 changed files with 118 additions and 10 deletions

View file

@ -10,8 +10,10 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
### Added
- Turtle decoder
- `describes?/1` on `RDF.Data` protocol and all RDF data structures which check
if statements about a given resource exist
- `RDF.Data.descriptions/1` which returns all descriptions within a RDF data structure
- `RDF.Description.first/2` which returns a single object a predicate of a `RDF.Description`
- `RDF.Description.first/2` which returns a single object to a predicate of a `RDF.Description`
- `RDF.Description.objects/2` with custom filter function
- `RDF.bnode?/1` which checks if the given value is a blank node

View file

@ -37,9 +37,9 @@ defprotocol RDF.Data do
def include?(data, statements)
@doc """
Returns the list of all statements of a RDF data structure.
Checks if a RDF data structure contains statements about the given resource.
"""
def statements(data)
def describes?(data, subject)
@doc """
Returns a `RDF.Description` of the given subject.
@ -57,6 +57,11 @@ defprotocol RDF.Data do
"""
def descriptions(data)
@doc """
Returns the list of all statements of a RDF data structure.
"""
def statements(data)
@doc """
Returns the set of all resources which are subject of the statements of a RDF data structure.
"""
@ -129,7 +134,8 @@ defimpl RDF.Data, for: RDF.Description do
def include?(description, statements),
do: RDF.Description.include?(description, statements)
def statements(description), do: RDF.Description.statements(description)
def describes?(description, subject),
do: RDF.Description.describes?(description, subject)
def description(%RDF.Description{subject: subject} = description, s) do
with ^subject <- RDF.Statement.convert_subject(s) do
@ -141,6 +147,8 @@ defimpl RDF.Data, for: RDF.Description do
def descriptions(description), do: [description]
def statements(description), do: RDF.Description.statements(description)
def subjects(%RDF.Description{subject: subject}), do: MapSet.new([subject])
def predicates(description), do: RDF.Description.predicates(description)
def objects(description), do: RDF.Description.objects(description)
@ -193,13 +201,16 @@ defimpl RDF.Data, for: RDF.Graph do
def include?(graph, statements), do: RDF.Graph.include?(graph, statements)
def statements(graph), do: RDF.Graph.statements(graph)
def describes?(graph, subject),
do: RDF.Graph.describes?(graph, subject)
def description(graph, subject),
do: RDF.Graph.description(graph, subject) || RDF.Description.new(subject)
def descriptions(graph), do: RDF.Graph.descriptions(graph)
def statements(graph), do: RDF.Graph.statements(graph)
def subjects(graph), do: RDF.Graph.subjects(graph)
def predicates(graph), do: RDF.Graph.predicates(graph)
def objects(graph), do: RDF.Graph.objects(graph)
@ -231,7 +242,8 @@ defimpl RDF.Data, for: RDF.Dataset do
def include?(dataset, statements), do: RDF.Dataset.include?(dataset, statements)
def statements(dataset), do: RDF.Dataset.statements(dataset)
def describes?(dataset, subject),
do: RDF.Dataset.who_describes(dataset, subject) != []
def description(dataset, subject) do
with subject = RDF.Statement.convert_subject(subject) do
@ -250,6 +262,8 @@ defimpl RDF.Data, for: RDF.Dataset do
|> Enum.map(&(description(dataset, &1)))
end
def statements(dataset), do: RDF.Dataset.statements(dataset)
def subjects(dataset), do: RDF.Dataset.subjects(dataset)
def predicates(dataset), do: RDF.Dataset.predicates(dataset)
def objects(dataset), do: RDF.Dataset.objects(dataset)

View file

@ -683,6 +683,47 @@ defmodule RDF.Dataset do
do: include?(dataset, {subject, predicate, object}, graph_context)
@doc """
Checks if a graph of a `RDF.Dataset` contains statements about the given resource.
## Examples
iex> RDF.Dataset.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Dataset.describes?(EX.S1)
true
iex> RDF.Dataset.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Dataset.describes?(EX.S2)
false
"""
def describes?(%RDF.Dataset{graphs: graphs}, subject, graph_context \\ nil) do
with graph_context = convert_graph_name(graph_context) do
if graph = graphs[graph_context] do
Graph.describes?(graph, subject)
else
false
end
end
end
@doc """
Returns the names of all graphs of a `RDF.Dataset` containing statements about the given subject.
## Examples
iex> dataset = RDF.Dataset.new([
...> {EX.S1, EX.p, EX.O},
...> {EX.S2, EX.p, EX.O},
...> {EX.S1, EX.p, EX.O, EX.Graph1},
...> {EX.S2, EX.p, EX.O, EX.Graph2}])
...> RDF.Dataset.who_describes(dataset, EX.S1)
[nil, RDF.uri(EX.Graph1)]
"""
def who_describes(%RDF.Dataset{graphs: graphs}, subject) do
with subject = convert_subject(subject) do
graphs
|> Map.values
|> Stream.filter(&Graph.describes?(&1, subject))
|> Enum.map(&(&1.name))
end
end
defimpl Enumerable do
def member?(graph, statement), do: {:ok, RDF.Dataset.include?(graph, statement)}
def count(graph), do: {:ok, RDF.Dataset.statement_count(graph)}

View file

@ -552,6 +552,23 @@ defmodule RDF.Description do
def include?(%RDF.Description{}, _), do: false
@doc """
Checks if a `RDF.Description` has the given resource as subject.
## Examples
iex> RDF.Description.new(EX.S1, EX.p1, EX.O1) |> RDF.Description.describes?(EX.S1)
true
iex> RDF.Description.new(EX.S1, EX.p1, EX.O1) |> RDF.Description.describes?(EX.S2)
false
"""
def describes?(%RDF.Description{subject: subject}, other_subject) do
with other_subject = convert_subject(other_subject) do
subject == other_subject
end
end
defimpl Enumerable do
def member?(desc, triple), do: {:ok, RDF.Description.include?(desc, triple)}
def count(desc), do: {:ok, RDF.Description.count(desc)}

View file

@ -582,6 +582,22 @@ defmodule RDF.Graph do
end
end
@doc """
Checks if a `RDF.Graph` contains statements about the given resource.
## Examples
iex> RDF.Graph.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Graph.describes?(EX.S1)
true
iex> RDF.Graph.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Graph.describes?(EX.S2)
false
"""
def describes?(%RDF.Graph{descriptions: descriptions}, subject) do
with subject = convert_subject(subject) do
Map.has_key?(descriptions, subject)
end
end
defimpl Enumerable do
def member?(desc, triple), do: {:ok, RDF.Graph.include?(desc, triple)}

View file

@ -91,8 +91,9 @@ defmodule RDF.DataTest do
refute RDF.Data.include?(description, {EX.Other, EX.p1, EX.O2})
end
test "statements", %{description: description} do
assert RDF.Data.statements(description) == Description.statements(description)
test "describes?", %{description: description} do
assert RDF.Data.describes?(description, EX.S)
refute RDF.Data.describes?(description, EX.Other)
end
test "description when the requested subject matches the Description.subject",
@ -111,6 +112,10 @@ defmodule RDF.DataTest do
assert RDF.Data.descriptions(description) == [description]
end
test "statements", %{description: description} do
assert RDF.Data.statements(description) == Description.statements(description)
end
test "subjects", %{description: description} do
assert RDF.Data.subjects(description) == MapSet.new([uri(EX.S)])
end
@ -215,8 +220,10 @@ defmodule RDF.DataTest do
refute RDF.Data.include?(graph, {EX.Other, EX.p1, EX.O2})
end
test "statements", %{graph: graph} do
assert RDF.Data.statements(graph) == Graph.statements(graph)
test "describes?", %{graph: graph} do
assert RDF.Data.describes?(graph, EX.S)
assert RDF.Data.describes?(graph, EX.S2)
refute RDF.Data.describes?(graph, EX.Other)
end
test "description when a description is present",
@ -234,6 +241,10 @@ defmodule RDF.DataTest do
[description, EX.S2 |> EX.p2(EX.O3, EX.O4)]
end
test "statements", %{graph: graph} do
assert RDF.Data.statements(graph) == Graph.statements(graph)
end
test "subjects", %{graph: graph} do
assert RDF.Data.subjects(graph) == MapSet.new([uri(EX.S), uri(EX.S2)])
end
@ -321,6 +332,13 @@ defmodule RDF.DataTest do
refute RDF.Data.include?(dataset, {EX.Other, EX.p1, EX.O2})
end
test "describes?", %{dataset: dataset} do
assert RDF.Data.describes?(dataset, EX.S)
assert RDF.Data.describes?(dataset, EX.S2)
assert RDF.Data.describes?(dataset, EX.S3)
refute RDF.Data.describes?(dataset, EX.Other)
end
test "description when a description is present",
%{dataset: dataset, description: description} do
description_aggregate = Description.add(description, {EX.S, EX.p3, EX.O5})