core: Access behaviour for Graph
This commit is contained in:
parent
ebd751827f
commit
6a9daa30e6
2 changed files with 108 additions and 1 deletions
|
@ -8,6 +8,8 @@ defmodule RDF.Graph do
|
||||||
"""
|
"""
|
||||||
defstruct name: nil, descriptions: %{}
|
defstruct name: nil, descriptions: %{}
|
||||||
|
|
||||||
|
@behaviour Access
|
||||||
|
|
||||||
alias RDF.{Description, Triple}
|
alias RDF.{Description, Triple}
|
||||||
|
|
||||||
@type t :: module
|
@type t :: module
|
||||||
|
@ -155,6 +157,103 @@ defmodule RDF.Graph do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def put(graph, subject, predications = {_predicate, _objects}),
|
||||||
|
do: put(graph, subject, [predications])
|
||||||
|
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Fetches the description of the given subject.
|
||||||
|
|
||||||
|
When the subject can not be found `:error` is returned.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) |>
|
||||||
|
...> RDF.Graph.fetch(EX.S1)
|
||||||
|
{:ok, RDF.Description.new({EX.S1, EX.P1, EX.O1})}
|
||||||
|
iex> RDF.Graph.fetch(RDF.Graph.new, EX.foo)
|
||||||
|
:error
|
||||||
|
"""
|
||||||
|
def fetch(%RDF.Graph{descriptions: descriptions}, subject) do
|
||||||
|
Access.fetch(descriptions, Triple.convert_subject(subject))
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets the description of the given subject.
|
||||||
|
|
||||||
|
When the subject can not be found the optionally given default value or `nil` is returned.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) |>
|
||||||
|
...> RDF.Graph.get(EX.S1)
|
||||||
|
RDF.Description.new({EX.S1, EX.P1, EX.O1})
|
||||||
|
iex> RDF.Graph.get(RDF.Graph.new, EX.Foo)
|
||||||
|
nil
|
||||||
|
iex> RDF.Graph.get(RDF.Graph.new, EX.Foo, :bar)
|
||||||
|
:bar
|
||||||
|
"""
|
||||||
|
def get(graph = %RDF.Graph{}, subject, default \\ nil) do
|
||||||
|
case fetch(graph, subject) do
|
||||||
|
{:ok, value} -> value
|
||||||
|
:error -> default
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Gets and updates the description of the given subject, in a single pass.
|
||||||
|
|
||||||
|
Invokes the passed function on the `RDF.Description` of the given subject;
|
||||||
|
this function should return either `{description_to_return, new_description}` or `:pop`.
|
||||||
|
|
||||||
|
If the passed function returns `{description_to_return, new_description}`, the
|
||||||
|
return value of `get_and_update` is `{description_to_return, new_graph}` where
|
||||||
|
`new_graph` is the input `Graph` updated with `new_description` for
|
||||||
|
the given subject.
|
||||||
|
|
||||||
|
If the passed function returns `:pop` the description for the given subject is
|
||||||
|
removed and a `{removed_description, new_graph}` tuple gets returned.
|
||||||
|
|
||||||
|
# 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)}
|
||||||
|
"""
|
||||||
|
def get_and_update(graph = %RDF.Graph{}, subject, fun) do
|
||||||
|
with triple_subject = Triple.convert_subject(subject) do
|
||||||
|
case fun.(get(graph, triple_subject)) do
|
||||||
|
{old_description, new_description} ->
|
||||||
|
{old_description, put(graph, triple_subject, new_description)}
|
||||||
|
:pop -> pop(graph, triple_subject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@doc """
|
||||||
|
Pops the description of the given subject.
|
||||||
|
|
||||||
|
When the subject can not be found the optionally given default value or `nil` is returned.
|
||||||
|
|
||||||
|
# Examples
|
||||||
|
|
||||||
|
iex> RDF.Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) |>
|
||||||
|
...> RDF.Graph.pop(EX.S1)
|
||||||
|
{RDF.Description.new({EX.S1, EX.P1, EX.O1}), RDF.Graph.new({EX.S2, EX.P2, EX.O2})}
|
||||||
|
iex> RDF.Graph.pop(RDF.Graph.new({EX.S, EX.P, EX.O}), EX.Missing)
|
||||||
|
{nil, RDF.Graph.new({EX.S, EX.P, EX.O})}
|
||||||
|
"""
|
||||||
|
def pop(graph = %RDF.Graph{name: name, descriptions: descriptions}, subject) do
|
||||||
|
case Access.pop(descriptions, Triple.convert_subject(subject)) do
|
||||||
|
{nil, _} ->
|
||||||
|
{nil, graph}
|
||||||
|
{description, new_descriptions} ->
|
||||||
|
{description, %RDF.Graph{name: name, descriptions: new_descriptions}}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def subject_count(graph), do: Enum.count(graph.descriptions)
|
def subject_count(graph), do: Enum.count(graph.descriptions)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ defmodule RDF.GraphTest do
|
||||||
doctest RDF.Graph
|
doctest RDF.Graph
|
||||||
|
|
||||||
alias RDF.{Graph, Description}
|
alias RDF.{Graph, Description}
|
||||||
import RDF, only: [uri: 1, literal: 1, bnode: 1]
|
import RDF, only: [uri: 1, bnode: 1]
|
||||||
|
|
||||||
|
|
||||||
def graph, do: unnamed_graph
|
def graph, do: unnamed_graph
|
||||||
|
@ -220,4 +220,12 @@ defmodule RDF.GraphTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "Access behaviour" do
|
||||||
|
test "access with the [] operator" do
|
||||||
|
assert Graph.new[EX.Subject] == nil
|
||||||
|
assert Graph.new({EX.S, EX.p, EX.O})[EX.S] ==
|
||||||
|
Description.new({EX.S, EX.p, EX.O})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue