Add RDF.Description.update/4

This commit is contained in:
Marcel Otto 2019-10-23 17:31:21 +02:00
parent 2cfa89125f
commit 623577b35e
3 changed files with 80 additions and 6 deletions

View file

@ -9,6 +9,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
### Added
- `RDF.Description.update/4` updates the objects of a predicate in a description
with a custom update function
- `RDF.Description.take/2` creates a description from another one by limiting
its statements to a set of predicates
- `RDF.Graph.take/3` creates a graph from another one by limiting

View file

@ -367,13 +367,49 @@ defmodule RDF.Description do
|> List.first
end
@doc """
Updates the objects of the `predicate` in `description` with the given function.
# def update(description = %RDF.Description{}, predicate, initial \\ [], fun) do
# triple_predicate = coerce_predicate(predicate)
# description.predicates
# |> Map.update(triple_predicate, initial, fn objects ->
# end)
# end
If `predicate` is present in `description` with `objects` as value,
`fun` is invoked with argument `objects` and its result is used as the new
list of objects of `predicate`. If `predicate` is not present in `description`,
`initial` is inserted as the `objects` of `predicate`. The initial value will
not be passed through the update function.
The initial value and the returned objects by the update function will automatically
coerced to proper RDF object values before added.
## Examples
iex> RDF.Description.new({EX.S, EX.p, EX.O}) |>
...> RDF.Description.update(EX.p, fn objects -> [EX.O2 | objects] end)
RDF.Description.new([{EX.S, EX.p, EX.O}, {EX.S, EX.p, EX.O2}])
iex> RDF.Description.new(EX.S) |>
...> RDF.Description.update(EX.p, EX.O, fn _ -> EX.O2 end)
RDF.Description.new({EX.S, EX.p, EX.O})
"""
def update(description = %RDF.Description{}, predicate, initial \\ nil, fun) do
predicate = coerce_predicate(predicate)
case get(description, predicate) do
nil ->
if initial do
put(description, predicate, initial)
else
description
end
objects ->
objects
|> fun.()
|> List.wrap()
|> case do
[] -> delete_predicates(description, predicate)
objects -> put(description, predicate, objects)
end
end
end
@doc """

View file

@ -317,6 +317,42 @@ defmodule RDF.DescriptionTest do
end
end
describe "update/4" do
test "list values returned from the update function become new coerced objects of the predicate" do
assert Description.new(EX.S, EX.P, [EX.O1, EX.O2])
|> Description.update(EX.P,
fn [_object | other] -> [EX.O3 | other] end) ==
Description.new(EX.S, EX.P, [EX.O3, EX.O2])
end
test "single values returned from the update function becomes new object of the predicate" do
assert Description.new(EX.S, EX.P, [EX.O1, EX.O2])
|> Description.update(EX.P, fn _ -> EX.O3 end) ==
Description.new(EX.S, EX.P, EX.O3)
end
test "returning an empty list or nil from the update function causes a removal of the predications" do
description = EX.S
|> EX.p(EX.O1, EX.O2)
assert description
|> Description.update(EX.p, fn _ -> [] end) ==
Description.new(EX.S, {EX.p, []})
assert description
|> Description.update(EX.p, fn _ -> nil end) ==
Description.new(EX.S, {EX.p, []})
end
test "when the property is not present the initial object value is added for the predicate and the update function not called" do
fun = fn _ -> raise "should not be called" end
assert Description.new(EX.S)
|> Description.update(EX.P, EX.O, fun) ==
Description.new(EX.S, EX.P, EX.O)
assert Description.new(EX.S)
|> Description.update(EX.P, fun) ==
Description.new(EX.S)
end
end
test "pop" do
assert Description.pop(Description.new(EX.S)) == {nil, Description.new(EX.S)}