Extract map/2 function from values/2 on all RDF data structures

and add support for RDF.PropertyMaps on values/2 instead
This commit is contained in:
Marcel Otto 2020-10-10 15:45:25 +02:00
parent 2fbf57a172
commit a49229384e
14 changed files with 350 additions and 109 deletions

View file

@ -59,6 +59,11 @@ are specified.
of overwriting only statements with the same subject and predicate, which was
almost never the expected behaviour. This is fixed now by relying on the new
`put/2` behaviour.
- the `values/2` functions of `RDF.Statement`, `RDF.Triple`, `RDF.Quad`, `RDF.Description`,
`RDF.Graph` and `RDF.Dataset` now accept on their second argument an optional
`RDF.PropertyMap`which will be used to map predicates accordingly; the variant of
these `values/2` functions to provide a custom mapping function was extracted into
a new function `map/2` on all of these modules
- for consistency reasons the internal `:id` struct field of `RDF.BlankNode` was renamed
to `:value`
- allow the `base_iri` of `RDF.Vocabulary.Namespace`s to end with a `.` to support

View file

@ -94,13 +94,16 @@ defprotocol RDF.Data do
@doc """
Returns a nested map of the native Elixir values of a RDF data structure.
When the optional `property_map` argument is given, predicates will be mapped
to the terms defined in the `RDF.PropertyMap` if present.
"""
def values(data)
def values(data, property_map \\ nil)
@doc """
Returns a nested map of the native Elixir values of a RDF data structure with values mapped with the given function.
Returns a map representation of a RDF data structure where each element from its statements is mapped with the given function.
"""
def values(data, mapping)
def map(data, fun)
@doc """
Checks if two RDF data structures are equal.
@ -191,8 +194,11 @@ defimpl RDF.Data, for: RDF.Description do
def subject_count(_), do: 1
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 values(description, property_map \\ nil),
do: RDF.Description.values(description, property_map)
def map(description, fun), do: RDF.Description.map(description, fun)
def equal?(description, %RDF.Description{} = other_description) do
RDF.Description.equal?(description, other_description)
@ -273,8 +279,8 @@ defimpl RDF.Data, for: RDF.Graph do
def subject_count(graph), do: RDF.Graph.subject_count(graph)
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 values(graph, property_map \\ nil), do: RDF.Graph.values(graph, property_map)
def map(graph, fun), do: RDF.Graph.map(graph, fun)
def equal?(graph, %RDF.Description{} = description),
do: RDF.Data.equal?(description, graph)
@ -348,8 +354,8 @@ defimpl RDF.Data, for: RDF.Dataset do
def subject_count(dataset), do: dataset |> subjects |> Enum.count()
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 values(dataset, property_map \\ nil), do: RDF.Dataset.values(dataset, property_map)
def map(dataset, fun), do: RDF.Dataset.map(dataset, fun)
def equal?(dataset, %RDF.Description{} = description) do
with [graph] <- RDF.Dataset.graphs(dataset) do

View file

@ -17,8 +17,8 @@ defmodule RDF.Dataset do
@behaviour Access
alias RDF.{Graph, Description, IRI, Statement}
import RDF.Statement
alias RDF.{Graph, Description, IRI, Statement, PropertyMap}
import RDF.Statement, only: [coerce_subject: 1, coerce_graph_name: 1]
import RDF.Utils
@type graph_name :: IRI.t() | nil
@ -761,10 +761,8 @@ defmodule RDF.Dataset do
@doc """
Returns a nested map of the native Elixir values of a `RDF.Dataset`.
The optional second argument allows to specify a custom mapping with a function
which will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate`, `:object`,
or `graph_name` while `rdf_term` is the RDF term to be mapped.
When the optional `property_map` argument is given, predicates will be mapped
to the terms defined in the `RDF.PropertyMap` if present.
## Examples
@ -783,12 +781,35 @@ defmodule RDF.Dataset do
}
}
"""
@spec values(t, PropertyMap.t() | nil) :: map
def values(dataset, property_map \\ nil)
def values(%__MODULE__{} = dataset, nil) do
map(dataset, &Statement.default_term_mapping/1)
end
def values(%__MODULE__{} = dataset, %PropertyMap{} = property_map) do
map(dataset, Statement.default_property_mapping(property_map))
end
@doc """
Returns a nested map of a `RDF.Dataset` where each element from its quads is mapped with the given function.
The function `fun` will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate`, `:object` or
`:graph_name` while `rdf_term` is the RDF term to be mapped. When the given function
returns `nil` this will be interpreted as an error and will become the overhaul
result of the `map/2` call.
## Examples
iex> [
...> {~I<http://example.com/S>, ~I<http://example.com/p>, ~L"Foo", ~I<http://example.com/Graph>},
...> {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.XSD.integer(42), }
...> ]
...> |> RDF.Dataset.new()
...> |> RDF.Dataset.values(fn
...> |> RDF.Dataset.map(fn
...> {:graph_name, graph_name} ->
...> graph_name
...> {:predicate, predicate} ->
@ -810,12 +831,12 @@ defmodule RDF.Dataset do
}
"""
@spec values(t, Statement.term_mapping()) :: map
def values(dataset, mapping \\ &Statement.default_term_mapping/1)
@spec map(t, Statement.term_mapping()) :: map
def map(dataset, fun)
def values(%__MODULE__{} = dataset, mapping) do
def map(%__MODULE__{} = dataset, fun) do
Map.new(dataset.graphs, fn {graph_name, graph} ->
{mapping.({:graph_name, graph_name}), Graph.values(graph, mapping)}
{fun.({:graph_name, graph_name}), Graph.map(graph, fun)}
end)
end

View file

@ -15,7 +15,9 @@ defmodule RDF.Description do
@behaviour Access
import RDF.Statement
import RDF.Statement,
only: [coerce_subject: 1, coerce_predicate: 1, coerce_predicate: 2, coerce_object: 1]
alias RDF.{Statement, Triple, PropertyMap}
@type t :: %__MODULE__{
@ -719,12 +721,11 @@ defmodule RDF.Description do
Returns a map of the native Elixir values of a `RDF.Description`.
The subject is not part of the result. It can be converted separately with
`RDF.Term.value/1`.
`RDF.Term.value/1`, or, if you want the subject in an outer map, just put the
the description in a graph and use `RDF.Graph.values/2`.
The optional second argument allows to specify a custom mapping with a function
which will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:predicate` or `:object`,
while `rdf_term` is the RDF term to be mapped.
When the optional `property_map` argument is given, predicates will be mapped
to the terms defined in the `RDF.PropertyMap` if present.
## Examples
@ -733,7 +734,37 @@ defmodule RDF.Description do
%{"http://example.com/p" => ["Foo"]}
iex> RDF.Description.new(~I<http://example.com/S>, init: {~I<http://example.com/p>, ~L"Foo"})
...> |> RDF.Description.values(fn
...> |> RDF.Description.values(PropertyMap.new(p: ~I<http://example.com/p>))
%{p: ["Foo"]}
"""
@spec values(t, PropertyMap.t() | nil) :: map
def values(description, property_map \\ nil)
def values(%__MODULE__{} = description, nil) do
map(description, &Statement.default_term_mapping/1)
end
def values(%__MODULE__{} = description, %PropertyMap{} = property_map) do
map(description, Statement.default_property_mapping(property_map))
end
@doc """
Returns a map of a `RDF.Description` where each element from its triples is mapped with the given function.
The subject is not part of the result. If you want the subject in an outer map,
just put the the description in a graph and use `RDF.Graph.map/2`.
The function `fun` will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:predicate` or `:object`, while
`rdf_term` is the RDF term to be mapped. When the given function returns
`nil` this will be interpreted as an error and will become the overhaul result
of the `map/2` call.
## Examples
iex> RDF.Description.new(~I<http://example.com/S>, init: {~I<http://example.com/p>, ~L"Foo"})
...> |> RDF.Description.map(fn
...> {:predicate, predicate} ->
...> predicate
...> |> to_string()
@ -746,14 +777,14 @@ defmodule RDF.Description do
%{p: ["Foo"]}
"""
@spec values(t, Statement.term_mapping()) :: map
def values(description, mapping \\ &Statement.default_term_mapping/1)
@spec map(t, Statement.term_mapping()) :: map
def map(description, fun)
def values(%__MODULE__{} = description, mapping) do
def map(%__MODULE__{} = description, fun) do
Map.new(description.predications, fn {predicate, objects} ->
{
mapping.({:predicate, predicate}),
objects |> Map.keys() |> Enum.map(&mapping.({:object, &1}))
fun.({:predicate, predicate}),
objects |> Map.keys() |> Enum.map(&fun.({:object, &1}))
}
end)
end

View file

@ -15,9 +15,9 @@ defmodule RDF.Graph do
@behaviour Access
import RDF.Statement
import RDF.Statement, only: [coerce_subject: 1, coerce_graph_name: 1]
import RDF.Utils
alias RDF.{Description, IRI, PrefixMap, Statement}
alias RDF.{Description, IRI, PrefixMap, Statement, PropertyMap}
@type graph_description :: %{Statement.subject() => Description.t()}
@ -851,10 +851,8 @@ defmodule RDF.Graph do
@doc """
Returns a nested map of the native Elixir values of a `RDF.Graph`.
The optional second argument allows to specify a custom mapping with a function
which will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate` or `:object`,
while `rdf_term` is the RDF term to be mapped.
When the optional `property_map` argument is given, predicates will be mapped
to the terms defined in the `RDF.PropertyMap` if present.
## Examples
@ -872,7 +870,40 @@ defmodule RDF.Graph do
...> {~I<http://example.com/S1>, ~I<http://example.com/p>, ~L"Foo"},
...> {~I<http://example.com/S2>, ~I<http://example.com/p>, RDF.XSD.integer(42)}
...> ])
...> |> RDF.Graph.values(fn
...> |> RDF.Graph.values(PropertyMap.new(p: ~I<http://example.com/p>))
%{
"http://example.com/S1" => %{p: ["Foo"]},
"http://example.com/S2" => %{p: [42]}
}
"""
@spec values(t, PropertyMap.t() | nil) :: map
def values(graph, property_map \\ nil)
def values(%__MODULE__{} = graph, nil) do
map(graph, &Statement.default_term_mapping/1)
end
def values(%__MODULE__{} = graph, %PropertyMap{} = property_map) do
map(graph, Statement.default_property_mapping(property_map))
end
@doc """
Returns a nested map of a `RDF.Graph` where each element from its triples is mapped with the given function.
The function `fun` will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate` or `:object`,
while `rdf_term` is the RDF term to be mapped. When the given function returns
`nil` this will be interpreted as an error and will become the overhaul result
of the `map/2` call.
## Examples
iex> RDF.Graph.new([
...> {~I<http://example.com/S1>, ~I<http://example.com/p>, ~L"Foo"},
...> {~I<http://example.com/S2>, ~I<http://example.com/p>, RDF.XSD.integer(42)}
...> ])
...> |> RDF.Graph.map(fn
...> {:predicate, predicate} ->
...> predicate
...> |> to_string()
@ -888,14 +919,14 @@ defmodule RDF.Graph do
}
"""
@spec values(t, Statement.term_mapping()) :: map
def values(graph, mapping \\ &Statement.default_term_mapping/1)
@spec map(t, Statement.term_mapping()) :: map
def map(description, fun)
def values(%__MODULE__{} = graph, mapping) do
def map(%__MODULE__{} = graph, fun) do
Map.new(graph.descriptions, fn {subject, description} ->
{
mapping.({:subject, subject}),
Description.values(description, mapping)
fun.({:subject, subject}),
Description.map(description, fun)
}
end)
end

View file

@ -8,8 +8,12 @@ defmodule RDF.Quad do
alias RDF.{Statement, PropertyMap}
@type t ::
{Statement.subject(), Statement.predicate(), Statement.object(), Statement.graph_name()}
@type t :: {
Statement.subject(),
Statement.predicate(),
Statement.object(),
Statement.graph_name()
}
@type t_values :: {String.t(), String.t(), any, String.t()}
@ -93,14 +97,10 @@ defmodule RDF.Quad do
@doc """
Returns a tuple of native Elixir values from a `RDF.Quad` of RDF terms.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
When the optional `property_map` argument is given, predicates will be mapped
to the terms defined in the `RDF.PropertyMap` if present.
The optional second argument allows to specify a custom mapping with a function
which will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate`, `:object` or
`:graph_name`, while `rdf_term` is the RDF term to be mapped. When the given
function returns `nil` this will be interpreted as an error and will become
the overhaul result of the `values/2` call.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
## Examples
@ -108,7 +108,36 @@ defmodule RDF.Quad do
{"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"}
iex> {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
...> |> RDF.Quad.values(fn
...> |> RDF.Quad.values(PropertyMap.new(p: ~I<http://example.com/p>))
{"http://example.com/S", :p, 42, "http://example.com/Graph"}
"""
@spec values(t, PropertyMap.t() | nil) :: t_values | nil
def values(quad, property_map \\ nil)
def values(quad, nil) do
map(quad, &Statement.default_term_mapping/1)
end
def values(quad, %PropertyMap{} = property_map) do
map(quad, Statement.default_property_mapping(property_map))
end
@doc """
Returns a tuple where each element from a `RDF.Quad` is mapped with the given function.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
The function `fun` will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate`, `:object` or
`:graph_name` while `rdf_term` is the RDF term to be mapped. When the given function
returns `nil` this will be interpreted as an error and will become the overhaul
result of the `map/2` call.
## Examples
iex> {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
...> |> RDF.Quad.map(fn
...> {:object, object} ->
...> RDF.Term.value(object)
...> {:graph_name, graph_name} ->
@ -119,22 +148,18 @@ defmodule RDF.Quad do
{:S, :p, 42, ~I<http://example.com/Graph>}
"""
@spec values(t | any, Statement.term_mapping()) :: t_values | nil
def values(quad, mapping \\ &Statement.default_term_mapping/1)
def values({subject, predicate, object, graph_name}, mapping) do
with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}),
predicate_value when not is_nil(predicate_value) <- mapping.({:predicate, predicate}),
object_value when not is_nil(object_value) <- mapping.({:object, object}),
graph_name_value <- mapping.({:graph_name, graph_name}) do
@spec map(t, Statement.term_mapping()) :: t_values | nil
def map({subject, predicate, object, graph_name}, fun) do
with subject_value when not is_nil(subject_value) <- fun.({:subject, subject}),
predicate_value when not is_nil(predicate_value) <- fun.({:predicate, predicate}),
object_value when not is_nil(object_value) <- fun.({:object, object}),
graph_name_value <- fun.({:graph_name, graph_name}) do
{subject_value, predicate_value, object_value, graph_name_value}
else
_ -> nil
end
end
def values(_, _), do: nil
@doc """
Checks if the given tuple is a valid RDF quad.

View file

@ -18,7 +18,8 @@ defmodule RDF.Statement do
@type coercible_object :: object | any
@type coercible_graph_name :: graph_name | atom | String.t()
@type qualified_term :: {atom, Term.t() | nil}
@type position :: :subject | :predicate | :object | :graph_name
@type qualified_term :: {position, Term.t() | nil}
@type term_mapping :: (qualified_term -> any | nil)
@type t :: Triple.t() | Quad.t()
@ -67,8 +68,8 @@ defmodule RDF.Statement do
@spec coerce_predicate(coercible_predicate, PropertyMap.t()) :: predicate
def coerce_predicate(term, context)
def coerce_predicate(term, %PropertyMap{} = context) when is_atom(term) do
PropertyMap.iri(context, term) || coerce_predicate(term)
def coerce_predicate(term, %PropertyMap{} = property_map) when is_atom(term) do
PropertyMap.iri(property_map, term) || coerce_predicate(term)
end
def coerce_predicate(term, _), do: coerce_predicate(term)
@ -98,6 +99,32 @@ defmodule RDF.Statement do
@doc """
Returns a tuple of native Elixir values from a `RDF.Statement` of RDF terms.
When the optional `property_map` argument is given, predicates will be mapped
to the terms defined in the `RDF.PropertyMap` if present.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
## Examples
iex> RDF.Statement.values {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42)}
{"http://example.com/S", "http://example.com/p", 42}
iex> RDF.Statement.values {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
{"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"}
iex> {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42)}
...> |> RDF.Statement.values(PropertyMap.new(p: ~I<http://example.com/p>))
{"http://example.com/S", :p, 42}
"""
@spec values(t, PropertyMap.t() | nil) :: Triple.t_values() | Quad.t_values() | nil
def values(quad, property_map \\ nil)
def values({_, _, _} = triple, property_map), do: Triple.values(triple, property_map)
def values({_, _, _, _} = quad, property_map), do: Quad.values(quad, property_map)
@doc """
Returns a tuple of native Elixir values from a `RDF.Statement` of RDF terms.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
The optional second argument allows to specify a custom mapping with a function
@ -109,13 +136,8 @@ defmodule RDF.Statement do
## Examples
iex> RDF.Statement.values {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42)}
{"http://example.com/S", "http://example.com/p", 42}
iex> RDF.Statement.values {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
{"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"}
iex> {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
...> |> RDF.Statement.values(fn
...> |> RDF.Statement.map(fn
...> {:subject, subject} ->
...> subject |> to_string() |> String.last()
...> {:predicate, predicate} ->
@ -128,11 +150,10 @@ defmodule RDF.Statement do
{"S", :p, 42, ~I<http://example.com/Graph>}
"""
@spec values(t | any, term_mapping) :: Triple.t_values() | Quad.t_values() | nil
def values(statement, mapping \\ &default_term_mapping/1)
def values({_, _, _} = triple, mapping), do: RDF.Triple.values(triple, mapping)
def values({_, _, _, _} = quad, mapping), do: RDF.Quad.values(quad, mapping)
def values(_, _), do: nil
@spec map(t, term_mapping()) :: Triple.t_values() | Quad.t_values() | nil | nil
def map(statement, fun)
def map({_, _, _} = triple, fun), do: RDF.Triple.map(triple, fun)
def map({_, _, _, _} = quad, fun), do: RDF.Quad.map(quad, fun)
@doc false
@spec default_term_mapping(qualified_term) :: any | nil
@ -140,6 +161,17 @@ defmodule RDF.Statement do
def default_term_mapping({:graph_name, nil}), do: nil
def default_term_mapping({_, term}), do: RDF.Term.value(term)
@spec default_property_mapping(PropertyMap.t()) :: term_mapping
def default_property_mapping(%PropertyMap{} = property_map) do
fn
{:predicate, predicate} ->
PropertyMap.term(property_map, predicate) || default_term_mapping({:predicate, predicate})
other ->
default_term_mapping(other)
end
end
@doc """
Checks if the given tuple is a valid RDF statement, i.e. RDF triple or quad.

View file

@ -87,14 +87,10 @@ defmodule RDF.Triple do
@doc """
Returns a tuple of native Elixir values from a `RDF.Triple` of RDF terms.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
When the optional `property_map` argument is given, predicates will be mapped
to the terms defined in the `RDF.PropertyMap` if present.
The optional second argument allows to specify a custom mapping with a function
which will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate` or `:object`,
while `rdf_term` is the RDF term to be mapped. When the given function returns
`nil` this will be interpreted as an error and will become the overhaul result
of the `values/2` call.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
## Examples
@ -102,28 +98,54 @@ defmodule RDF.Triple do
{"http://example.com/S", "http://example.com/p", 42}
iex> {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42)}
...> |> RDF.Triple.values(fn
...> |> RDF.Triple.values(PropertyMap.new(p: ~I<http://example.com/p>))
{"http://example.com/S", :p, 42}
"""
@spec values(t, PropertyMap.t() | nil) :: t_values | nil
def values(triple, property_map \\ nil)
def values(triple, nil) do
map(triple, &Statement.default_term_mapping/1)
end
def values(triple, %PropertyMap{} = property_map) do
map(triple, Statement.default_property_mapping(property_map))
end
@doc """
Returns a triple where each element from a `RDF.Triple` is mapped with the given function.
Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`.
The function `fun` will receive a tuple `{statement_position, rdf_term}` where
`statement_position` is one of the atoms `:subject`, `:predicate` or `:object`,
while `rdf_term` is the RDF term to be mapped. When the given function returns
`nil` this will be interpreted as an error and will become the overhaul result
of the `map/2` call.
## Examples
iex> {~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42)}
...> |> RDF.Triple.map(fn
...> {:object, object} -> RDF.Term.value(object)
...> {_, term} -> term |> to_string() |> String.last()
...> end)
{"S", "p", 42}
"""
@spec values(t | any, Statement.term_mapping()) :: t_values | nil
def values(triple, mapping \\ &Statement.default_term_mapping/1)
def values({subject, predicate, object}, mapping) do
with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}),
predicate_value when not is_nil(predicate_value) <- mapping.({:predicate, predicate}),
object_value when not is_nil(object_value) <- mapping.({:object, object}) do
@spec map(t, Statement.term_mapping()) :: t_values | nil
def map({subject, predicate, object}, fun) do
with subject_value when not is_nil(subject_value) <- fun.({:subject, subject}),
predicate_value when not is_nil(predicate_value) <- fun.({:predicate, predicate}),
object_value when not is_nil(object_value) <- fun.({:object, object}) do
{subject_value, predicate_value, object_value}
else
_ -> nil
end
end
def values(_, _), do: nil
@doc """
Checks if the given tuple is a valid RDF triple.

View file

@ -534,7 +534,7 @@ defmodule RDF.DataTest do
}
end
test "values/2", %{dataset: dataset} do
test "map/2", %{dataset: dataset} do
mapping = fn
{:graph_name, graph_name} ->
graph_name
@ -546,7 +546,7 @@ defmodule RDF.DataTest do
RDF.Term.value(term)
end
assert RDF.Data.values(dataset, mapping) ==
assert RDF.Data.map(dataset, mapping) ==
%{
nil => %{
RDF.Term.value(RDF.iri(EX.S)) => %{

View file

@ -1681,6 +1681,19 @@ defmodule RDF.DatasetTest do
end
test "values/2" do
assert Dataset.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2(), EX.graph()}])
|> Dataset.values(PropertyMap.new(p: EX.p())) ==
%{
nil => %{
RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]}
},
RDF.Term.value(EX.graph()) => %{
RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]}
}
}
end
test "map/2" do
mapping = fn
{:graph_name, graph_name} ->
graph_name
@ -1692,10 +1705,10 @@ defmodule RDF.DatasetTest do
RDF.Term.value(term)
end
assert Dataset.new() |> Dataset.values(mapping) == %{}
assert Dataset.new() |> Dataset.map(mapping) == %{}
assert Dataset.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2(), EX.graph()}])
|> Dataset.values(mapping) ==
|> Dataset.map(mapping) ==
%{
nil => %{
RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]}

View file

@ -839,6 +839,12 @@ defmodule RDF.DescriptionTest do
end
test "values/2" do
assert Description.new(EX.s(), init: {EX.s(), EX.p(), ~L"Foo"})
|> Description.values(PropertyMap.new(p: EX.p())) ==
%{p: ["Foo"]}
end
test "map/2" do
mapping = fn
{:predicate, predicate} ->
predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom()
@ -847,9 +853,9 @@ defmodule RDF.DescriptionTest do
RDF.Term.value(term)
end
assert Description.new(EX.s()) |> Description.values(mapping) == %{}
assert Description.new(EX.s()) |> Description.map(mapping) == %{}
assert Description.new(EX.s(), init: {EX.s(), EX.p(), ~L"Foo"}) |> Description.values(mapping) ==
assert Description.new(EX.s(), init: {EX.s(), EX.p(), ~L"Foo"}) |> Description.map(mapping) ==
%{p: ["Foo"]}
end

View file

@ -1252,6 +1252,15 @@ defmodule RDF.GraphTest do
end
test "values/2" do
assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}])
|> Graph.values(PropertyMap.new(p: EX.p())) ==
%{
RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]},
RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]}
}
end
test "map/2" do
mapping = fn
{:predicate, predicate} ->
predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom()
@ -1260,10 +1269,10 @@ defmodule RDF.GraphTest do
RDF.Term.value(term)
end
assert Graph.new() |> Graph.values(mapping) == %{}
assert Graph.new() |> Graph.map(mapping) == %{}
assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}])
|> Graph.values(mapping) ==
|> Graph.map(mapping) ==
%{
RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]},
RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]}

View file

@ -20,15 +20,36 @@ defmodule RDF.QuadTest do
end
test "with an invalid RDF.Quad" do
refute Quad.values({~I<http://example.com/S>, ~I<http://example.com/p>})
refute Quad.values({self(), self(), self(), self()})
end
end
test "values/2" do
describe "values/2" do
test "with a valid RDF.Quad and RDF.PropertyMap" do
assert Quad.values(
{~I<http://example.com/S>, ~I<http://example.com/p>, XSD.integer(42),
~I<http://example.com/Graph>},
PropertyMap.new(p: ~I<http://example.com/p>)
) ==
{"http://example.com/S", :p, 42, "http://example.com/Graph"}
assert Quad.values(
{~I<http://example.com/S>, ~I<http://example.com/p>, XSD.integer(42),
~I<http://example.com/Graph>},
PropertyMap.new()
) ==
{"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"}
end
test "with an invalid RDF.Triple" do
refute Quad.values({self(), self(), self(), self()}, PropertyMap.new())
end
end
test "map/2" do
assert {~I<http://example.com/S>, ~I<http://example.com/p>, XSD.integer(42),
~I<http://example.com/Graph>}
|> Quad.values(fn
|> Quad.map(fn
{:subject, subject} -> subject |> to_string() |> String.last() |> String.to_atom()
{:predicate, _} -> :p
{:object, object} -> object |> RDF.Term.value() |> Kernel.+(1)

View file

@ -12,14 +12,33 @@ defmodule RDF.TripleTest do
end
test "with an invalid RDF.Triple" do
refute Triple.values({~I<http://example.com/S>, ~I<http://example.com/p>})
refute Triple.values({self(), self(), self()})
end
end
test "values/2" do
describe "values/2" do
test "with a valid RDF.Triple and RDF.PropertyMap" do
assert Triple.values(
{~I<http://example.com/S>, ~I<http://example.com/p>, XSD.integer(42)},
PropertyMap.new(p: ~I<http://example.com/p>)
) ==
{"http://example.com/S", :p, 42}
assert Triple.values(
{~I<http://example.com/S>, ~I<http://example.com/p>, XSD.integer(42)},
PropertyMap.new()
) ==
{"http://example.com/S", "http://example.com/p", 42}
end
test "with an invalid RDF.Triple" do
refute Triple.values({self(), self(), self()}, PropertyMap.new())
end
end
test "map/2" do
assert {~I<http://example.com/S>, ~I<http://example.com/p>, XSD.integer(42)}
|> Triple.values(fn
|> Triple.map(fn
{:object, object} -> object |> RDF.Term.value() |> Kernel.+(1)
{_, term} -> term |> to_string() |> String.last()
end) ==