Support for RDF.PropertyMaps as :context opt on functions with input data
This commit is contained in:
parent
e681733652
commit
d0e5b625fd
13 changed files with 618 additions and 156 deletions
15
CHANGELOG.md
15
CHANGELOG.md
|
@ -18,6 +18,10 @@ are specified.
|
|||
|
||||
### Added
|
||||
|
||||
- `RDF.PropertyMap` which allow definition of atoms for RDF properties.
|
||||
Such property maps can be provided to all RDF data structure functions
|
||||
accepting input data with the `:context` opt, allowing the use of the atoms
|
||||
from the property map in the input data.
|
||||
- to `RDF.Description`
|
||||
- `RDF.Description.subject/1`
|
||||
- `RDF.Description.change_subject/2`
|
||||
|
@ -26,9 +30,11 @@ are specified.
|
|||
- `RDF.Graph.change_name/2`
|
||||
- `RDF.Graph.base_iri/1`
|
||||
- `RDF.Graph.prefixes/1`
|
||||
- `RDF.Graph.put_properties/3`
|
||||
- to `RDF.Dataset`
|
||||
- `RDF.Dataset.name/1`
|
||||
- `RDF.Dataset.change_name/2`
|
||||
- `RDF.Dataset.put_properties/3`
|
||||
- `RDF.IRI.append/2`
|
||||
|
||||
### Changed
|
||||
|
@ -41,7 +47,9 @@ are specified.
|
|||
- The `put/3` functions on `RDF.Graph` and `RDF.Dataset` now overwrite all
|
||||
statements with same subject. Previously only statements with the same subject
|
||||
AND predicate were overwritten, which was probably not the expected behaviour,
|
||||
since it's not inline with the common `put` semantics in Elixir.
|
||||
since it's not inline with the common `put` semantics in Elixir.
|
||||
A function with the previous behaviour was added on `RDF.Graph` and `RDF.Dataset`
|
||||
with the `put_properties/3` function.
|
||||
- **CAUTION: This means the `RDF.Graph.put/2` and `RDF.Dataset.put/2` function have become more destructive now when not specified otherwise.**
|
||||
- Note: Although one could argue, that following this route `RDF.Dataset.put/3`
|
||||
would consequently have to overwrite whole graphs, this was not implemented
|
||||
|
@ -54,7 +62,10 @@ are specified.
|
|||
- 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
|
||||
vocabularies which use dots in the IRIs for further structuring (eg. CIM-based formats like CGMES)
|
||||
vocabularies which use dots in the IRIs for further structuring (eg. CIM-based formats like CGMES)
|
||||
- `RDF.Triple.new/1` now also accepts four-element tuples and simple ignores fourth element
|
||||
- `RDF.Quad.new/1` now also accepts three-element tuples and simple assumes the fourth
|
||||
element to be `nil`
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
@ -56,15 +56,14 @@ defmodule RDF.Dataset do
|
|||
|
||||
"""
|
||||
@spec new(input | keyword) :: t
|
||||
def new(data_or_options)
|
||||
def new(data_or_opts)
|
||||
|
||||
def new(data_or_options)
|
||||
when is_list(data_or_options) and length(data_or_options) != 0 do
|
||||
if Keyword.keyword?(data_or_options) do
|
||||
{data, options} = Keyword.pop(data_or_options, :init)
|
||||
def new(data_or_opts) when is_list(data_or_opts) and length(data_or_opts) != 0 do
|
||||
if Keyword.keyword?(data_or_opts) do
|
||||
{data, options} = Keyword.pop(data_or_opts, :init)
|
||||
new(data, options)
|
||||
else
|
||||
new(data_or_options, [])
|
||||
new(data_or_opts, [])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -84,21 +83,21 @@ defmodule RDF.Dataset do
|
|||
|
||||
"""
|
||||
@spec new(input, keyword) :: t
|
||||
def new(data, options)
|
||||
def new(data, opts)
|
||||
|
||||
def new(%__MODULE__{} = graph, options) do
|
||||
%__MODULE__{graph | name: options |> Keyword.get(:name) |> coerce_graph_name()}
|
||||
def new(%__MODULE__{} = graph, opts) do
|
||||
%__MODULE__{graph | name: opts |> Keyword.get(:name) |> coerce_graph_name()}
|
||||
end
|
||||
|
||||
def new(data, options) do
|
||||
def new(data, opts) do
|
||||
%__MODULE__{}
|
||||
|> new(options)
|
||||
|> init(data)
|
||||
|> new(opts)
|
||||
|> init(data, opts)
|
||||
end
|
||||
|
||||
defp init(dataset, nil), do: dataset
|
||||
defp init(dataset, fun) when is_function(fun), do: add(dataset, fun.())
|
||||
defp init(dataset, data), do: add(dataset, data)
|
||||
defp init(dataset, nil, _), do: dataset
|
||||
defp init(dataset, fun, opts) when is_function(fun), do: add(dataset, fun.(), opts)
|
||||
defp init(dataset, data, opts), do: add(dataset, data, opts)
|
||||
|
||||
@doc """
|
||||
Returns the dataset name IRI of `dataset`.
|
||||
|
@ -143,13 +142,13 @@ defmodule RDF.Dataset do
|
|||
def add(dataset, input, opts \\ [])
|
||||
|
||||
def add(%__MODULE__{} = dataset, {_, _, _, graph} = quad, opts),
|
||||
do: do_add(dataset, destination_graph(opts, graph), quad)
|
||||
do: do_add(dataset, destination_graph(opts, graph), quad, opts)
|
||||
|
||||
def add(%__MODULE__{} = dataset, %Description{} = description, opts),
|
||||
do: do_add(dataset, destination_graph(opts), description)
|
||||
do: do_add(dataset, destination_graph(opts), description, opts)
|
||||
|
||||
def add(%__MODULE__{} = dataset, %Graph{} = graph, opts),
|
||||
do: do_add(dataset, destination_graph(opts, graph.name), graph)
|
||||
do: do_add(dataset, destination_graph(opts, graph.name), graph, opts)
|
||||
|
||||
def add(%__MODULE__{} = dataset, %__MODULE__{} = other_dataset, opts) do
|
||||
other_dataset
|
||||
|
@ -171,9 +170,9 @@ defmodule RDF.Dataset do
|
|||
end
|
||||
|
||||
def add(%__MODULE__{} = dataset, input, opts),
|
||||
do: do_add(dataset, destination_graph(opts), input)
|
||||
do: do_add(dataset, destination_graph(opts), input, opts)
|
||||
|
||||
defp do_add(dataset, graph_name, input) do
|
||||
defp do_add(dataset, graph_name, input, opts) do
|
||||
%__MODULE__{
|
||||
dataset
|
||||
| graphs:
|
||||
|
@ -181,9 +180,9 @@ defmodule RDF.Dataset do
|
|||
dataset.graphs,
|
||||
graph_name,
|
||||
# when new:
|
||||
fn -> Graph.new(input, name: graph_name) end,
|
||||
fn -> Graph.new(input, Keyword.put(opts, :name, graph_name)) end,
|
||||
# when update:
|
||||
fn graph -> Graph.add(graph, input) end
|
||||
fn graph -> Graph.add(graph, input, opts) end
|
||||
)
|
||||
}
|
||||
end
|
||||
|
@ -299,13 +298,13 @@ defmodule RDF.Dataset do
|
|||
def delete(dataset, input, opts \\ [])
|
||||
|
||||
def delete(%__MODULE__{} = dataset, {_, _, _, graph} = quad, opts),
|
||||
do: do_delete(dataset, destination_graph(opts, graph), quad)
|
||||
do: do_delete(dataset, destination_graph(opts, graph), quad, opts)
|
||||
|
||||
def delete(%__MODULE__{} = dataset, %Description{} = description, opts),
|
||||
do: do_delete(dataset, destination_graph(opts), description)
|
||||
do: do_delete(dataset, destination_graph(opts), description, opts)
|
||||
|
||||
def delete(%__MODULE__{} = dataset, %Graph{} = graph, opts),
|
||||
do: do_delete(dataset, destination_graph(opts, graph.name), graph)
|
||||
do: do_delete(dataset, destination_graph(opts, graph.name), graph, opts)
|
||||
|
||||
def delete(%__MODULE__{} = dataset, %__MODULE__{} = other_dataset, opts) do
|
||||
other_dataset
|
||||
|
@ -320,7 +319,7 @@ defmodule RDF.Dataset do
|
|||
end
|
||||
|
||||
def delete(%__MODULE__{} = dataset, input, opts) when not is_struct(input),
|
||||
do: do_delete(dataset, destination_graph(opts), input)
|
||||
do: do_delete(dataset, destination_graph(opts), input, opts)
|
||||
else
|
||||
def delete(_, %_{}, _), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
|
||||
|
@ -329,12 +328,12 @@ defmodule RDF.Dataset do
|
|||
end
|
||||
|
||||
def delete(%__MODULE__{} = dataset, input, opts),
|
||||
do: do_delete(dataset, destination_graph(opts), input)
|
||||
do: do_delete(dataset, destination_graph(opts), input, opts)
|
||||
end
|
||||
|
||||
defp do_delete(dataset, graph_name, input) do
|
||||
defp do_delete(dataset, graph_name, input, opts) do
|
||||
if existing_graph = dataset.graphs[graph_name] do
|
||||
new_graph = Graph.delete(existing_graph, input)
|
||||
new_graph = Graph.delete(existing_graph, input, opts)
|
||||
|
||||
%__MODULE__{
|
||||
dataset
|
||||
|
@ -677,13 +676,13 @@ defmodule RDF.Dataset do
|
|||
def include?(dataset, input, opts \\ [])
|
||||
|
||||
def include?(%__MODULE__{} = dataset, {_, _, _, graph} = quad, opts),
|
||||
do: do_include?(dataset, destination_graph(opts, graph), quad)
|
||||
do: do_include?(dataset, destination_graph(opts, graph), quad, opts)
|
||||
|
||||
def include?(%__MODULE__{} = dataset, %Description{} = description, opts),
|
||||
do: do_include?(dataset, destination_graph(opts), description)
|
||||
do: do_include?(dataset, destination_graph(opts), description, opts)
|
||||
|
||||
def include?(%__MODULE__{} = dataset, %Graph{} = graph, opts),
|
||||
do: do_include?(dataset, destination_graph(opts, graph.name), graph)
|
||||
do: do_include?(dataset, destination_graph(opts, graph.name), graph, opts)
|
||||
|
||||
def include?(%__MODULE__{} = dataset, %__MODULE__{} = other_dataset, opts) do
|
||||
other_dataset
|
||||
|
@ -698,7 +697,7 @@ defmodule RDF.Dataset do
|
|||
end
|
||||
|
||||
def include?(dataset, input, opts) when not is_struct(input),
|
||||
do: do_include?(dataset, destination_graph(opts), input)
|
||||
do: do_include?(dataset, destination_graph(opts), input, opts)
|
||||
else
|
||||
def include?(_, %_{}, _), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
|
||||
|
@ -706,12 +705,13 @@ defmodule RDF.Dataset do
|
|||
Enum.all?(input, &include?(dataset, &1, opts))
|
||||
end
|
||||
|
||||
def include?(dataset, input, opts), do: do_include?(dataset, destination_graph(opts), input)
|
||||
def include?(dataset, input, opts),
|
||||
do: do_include?(dataset, destination_graph(opts), input, opts)
|
||||
end
|
||||
|
||||
defp do_include?(%__MODULE__{} = dataset, graph_name, input) do
|
||||
defp do_include?(%__MODULE__{} = dataset, graph_name, input, opts) do
|
||||
if graph = dataset.graphs[graph_name] do
|
||||
Graph.include?(graph, input)
|
||||
Graph.include?(graph, input, opts)
|
||||
else
|
||||
false
|
||||
end
|
||||
|
|
|
@ -26,7 +26,7 @@ defmodule RDF.Description do
|
|||
@type predications :: %{Statement.predicate() => %{Statement.object() => nil}}
|
||||
|
||||
@type input ::
|
||||
Triple.coercible_t()
|
||||
Statement.coercible_t()
|
||||
| {
|
||||
Statement.coercible_predicate(),
|
||||
Statement.coercible_object() | [Statement.coercible_object()]
|
||||
|
@ -36,7 +36,7 @@ defmodule RDF.Description do
|
|||
Statement.coercible_object() | [Statement.coercible_object()]
|
||||
}
|
||||
| [
|
||||
Triple.coercible_t()
|
||||
Statement.coercible_t()
|
||||
| {
|
||||
Statement.coercible_predicate(),
|
||||
Statement.coercible_object() | [Statement.coercible_object()]
|
||||
|
@ -68,13 +68,15 @@ defmodule RDF.Description do
|
|||
def new(%__MODULE__{} = description, opts), do: new(description.subject, opts)
|
||||
|
||||
def new(subject, opts) do
|
||||
{data, opts} = Keyword.pop(opts, :init)
|
||||
|
||||
%__MODULE__{subject: coerce_subject(subject)}
|
||||
|> init(Keyword.get(opts, :init))
|
||||
|> init(data, opts)
|
||||
end
|
||||
|
||||
defp init(description, nil), do: description
|
||||
defp init(description, fun) when is_function(fun), do: add(description, fun.())
|
||||
defp init(description, data), do: add(description, data)
|
||||
defp init(description, nil, _), do: description
|
||||
defp init(description, fun, opts) when is_function(fun), do: add(description, fun.(), opts)
|
||||
defp init(description, data, opts), do: add(description, data, opts)
|
||||
|
||||
@doc """
|
||||
Returns the subject IRI or blank node of a description.
|
||||
|
@ -90,6 +92,14 @@ defmodule RDF.Description do
|
|||
%__MODULE__{description | subject: coerce_subject(new_subject)}
|
||||
end
|
||||
|
||||
defp context(nil), do: nil
|
||||
|
||||
defp context(opts) do
|
||||
if property_map = Keyword.get(opts, :context) do
|
||||
PropertyMap.new(property_map)
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Add statements to a `RDF.Description`.
|
||||
|
||||
|
@ -123,11 +133,11 @@ defmodule RDF.Description do
|
|||
end
|
||||
end
|
||||
|
||||
def add(%__MODULE__{} = description, {predicate, objects}, _opts) do
|
||||
def add(%__MODULE__{} = description, {predicate, objects}, opts) do
|
||||
normalized_objects =
|
||||
objects
|
||||
|> List.wrap()
|
||||
|> Map.new(fn object -> {coerce_object(object), nil} end)
|
||||
|> Map.new(&{coerce_object(&1), nil})
|
||||
|
||||
if Enum.empty?(normalized_objects) do
|
||||
description
|
||||
|
@ -137,7 +147,7 @@ defmodule RDF.Description do
|
|||
| predications:
|
||||
Map.update(
|
||||
description.predications,
|
||||
coerce_predicate(predicate),
|
||||
coerce_predicate(predicate, context(opts)),
|
||||
normalized_objects,
|
||||
fn objects ->
|
||||
Map.merge(objects, normalized_objects)
|
||||
|
@ -217,7 +227,7 @@ defmodule RDF.Description do
|
|||
def put(%__MODULE__{} = description, %__MODULE__{}, _opts), do: description
|
||||
|
||||
def put(%__MODULE__{} = description, input, opts) do
|
||||
put(description, description.subject |> new() |> add(input), opts)
|
||||
put(description, description.subject |> new() |> add(input, opts), opts)
|
||||
end
|
||||
|
||||
@doc """
|
||||
|
@ -243,8 +253,8 @@ defmodule RDF.Description do
|
|||
delete(description, {subject, predicate, objects}, opts)
|
||||
end
|
||||
|
||||
def delete(%__MODULE__{} = description, {predicate, objects}, _opts) do
|
||||
predicate = coerce_predicate(predicate)
|
||||
def delete(%__MODULE__{} = description, {predicate, objects}, opts) do
|
||||
predicate = coerce_predicate(predicate, context(opts))
|
||||
|
||||
if current_objects = Map.get(description.predications, predicate) do
|
||||
normalized_objects =
|
||||
|
@ -634,20 +644,20 @@ defmodule RDF.Description do
|
|||
@doc """
|
||||
Checks if the given `input` statements exist within `description`.
|
||||
"""
|
||||
@spec include?(t, input) :: boolean
|
||||
def include?(description, input)
|
||||
@spec include?(t, input, keyword) :: boolean
|
||||
def include?(description, input, opts \\ [])
|
||||
|
||||
def include?(%__MODULE__{} = description, {subject, predicate, objects}) do
|
||||
def include?(%__MODULE__{} = description, {subject, predicate, objects}, opts) do
|
||||
coerce_subject(subject) == description.subject &&
|
||||
include?(description, {predicate, objects})
|
||||
include?(description, {predicate, objects}, opts)
|
||||
end
|
||||
|
||||
def include?(%__MODULE__{} = description, {subject, predicate, objects, _}) do
|
||||
include?(description, {subject, predicate, objects})
|
||||
def include?(%__MODULE__{} = description, {subject, predicate, objects, _}, opts) do
|
||||
include?(description, {subject, predicate, objects}, opts)
|
||||
end
|
||||
|
||||
def include?(%__MODULE__{} = description, {predicate, objects}) do
|
||||
if existing_objects = description.predications[coerce_predicate(predicate)] do
|
||||
def include?(%__MODULE__{} = description, {predicate, objects}, opts) do
|
||||
if existing_objects = description.predications[coerce_predicate(predicate, context(opts))] do
|
||||
objects
|
||||
|> List.wrap()
|
||||
|> Enum.map(&coerce_object/1)
|
||||
|
@ -659,7 +669,8 @@ defmodule RDF.Description do
|
|||
|
||||
def include?(
|
||||
%__MODULE__{subject: subject, predications: predications},
|
||||
%__MODULE__{subject: subject} = input
|
||||
%__MODULE__{subject: subject} = input,
|
||||
_opts
|
||||
) do
|
||||
Enum.all?(input.predications, fn {predicate, objects} ->
|
||||
if existing_objects = predications[predicate] do
|
||||
|
@ -672,18 +683,18 @@ defmodule RDF.Description do
|
|||
end)
|
||||
end
|
||||
|
||||
def include?(%__MODULE__{}, %__MODULE__{}), do: false
|
||||
def include?(%__MODULE__{}, %__MODULE__{}, _), do: false
|
||||
|
||||
if Version.match?(System.version(), "~> 1.10") do
|
||||
def include?(description, input)
|
||||
def include?(description, input, opts)
|
||||
when is_list(input) or (is_map(input) and not is_struct(input)) do
|
||||
Enum.all?(input, &include?(description, &1))
|
||||
Enum.all?(input, &include?(description, &1, opts))
|
||||
end
|
||||
else
|
||||
def include?(_, %_{}), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
def include?(_, %_{}, _), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
|
||||
def include?(description, input) when is_list(input) or is_map(input) do
|
||||
Enum.all?(input, &include?(description, &1))
|
||||
def include?(description, input, opts) when is_list(input) or is_map(input) do
|
||||
Enum.all?(input, &include?(description, &1, opts))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
110
lib/rdf/graph.ex
110
lib/rdf/graph.ex
|
@ -71,15 +71,14 @@ defmodule RDF.Graph do
|
|||
|
||||
"""
|
||||
@spec new(input | keyword) :: t
|
||||
def new(data_or_options)
|
||||
def new(data_or_opts)
|
||||
|
||||
def new(data_or_options)
|
||||
when is_list(data_or_options) and length(data_or_options) != 0 do
|
||||
if Keyword.keyword?(data_or_options) do
|
||||
{data, options} = Keyword.pop(data_or_options, :init)
|
||||
def new(data_or_opts) when is_list(data_or_opts) and length(data_or_opts) != 0 do
|
||||
if Keyword.keyword?(data_or_opts) do
|
||||
{data, options} = Keyword.pop(data_or_opts, :init)
|
||||
new(data, options)
|
||||
else
|
||||
new(data_or_options, [])
|
||||
new(data_or_opts, [])
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -118,23 +117,23 @@ defmodule RDF.Graph do
|
|||
|
||||
"""
|
||||
@spec new(input, keyword) :: t
|
||||
def new(data, options)
|
||||
def new(data, opts)
|
||||
|
||||
def new(%__MODULE__{} = graph, options) do
|
||||
%__MODULE__{graph | name: options |> Keyword.get(:name) |> coerce_graph_name()}
|
||||
|> add_prefixes(Keyword.get(options, :prefixes))
|
||||
|> set_base_iri(Keyword.get(options, :base_iri))
|
||||
def new(%__MODULE__{} = graph, opts) do
|
||||
%__MODULE__{graph | name: opts |> Keyword.get(:name) |> coerce_graph_name()}
|
||||
|> add_prefixes(Keyword.get(opts, :prefixes))
|
||||
|> set_base_iri(Keyword.get(opts, :base_iri))
|
||||
end
|
||||
|
||||
def new(data, options) do
|
||||
def new(data, opts) do
|
||||
new()
|
||||
|> new(options)
|
||||
|> init(data)
|
||||
|> new(opts)
|
||||
|> init(data, opts)
|
||||
end
|
||||
|
||||
defp init(graph, nil), do: graph
|
||||
defp init(graph, fun) when is_function(fun), do: add(graph, fun.())
|
||||
defp init(graph, data), do: add(graph, data)
|
||||
defp init(graph, nil, _), do: graph
|
||||
defp init(graph, fun, opts) when is_function(fun), do: add(graph, fun.(), opts)
|
||||
defp init(graph, data, opts), do: add(graph, data, opts)
|
||||
|
||||
@doc """
|
||||
Removes all triples from `graph`.
|
||||
|
@ -337,43 +336,43 @@ defmodule RDF.Graph do
|
|||
use `RDF.Data.delete/2`.
|
||||
|
||||
"""
|
||||
@spec delete(t, input) :: t
|
||||
def delete(graph, input)
|
||||
@spec delete(t, input, keyword) :: t
|
||||
def delete(graph, input, opts \\ [])
|
||||
|
||||
def delete(%__MODULE__{} = graph, {subject, _, _} = triple),
|
||||
do: do_delete(graph, coerce_subject(subject), triple)
|
||||
def delete(%__MODULE__{} = graph, {subject, _, _} = triple, opts),
|
||||
do: do_delete(graph, coerce_subject(subject), triple, opts)
|
||||
|
||||
def delete(%__MODULE__{} = graph, {subject, predications}),
|
||||
do: do_delete(graph, coerce_subject(subject), predications)
|
||||
def delete(%__MODULE__{} = graph, {subject, predications}, opts),
|
||||
do: do_delete(graph, coerce_subject(subject), predications, opts)
|
||||
|
||||
def delete(graph, {subject, predicate, object, _}),
|
||||
do: delete(graph, {subject, predicate, object})
|
||||
def delete(graph, {subject, predicate, object, _}, opts),
|
||||
do: delete(graph, {subject, predicate, object}, opts)
|
||||
|
||||
def delete(%__MODULE__{} = graph, %Description{} = description),
|
||||
do: do_delete(graph, description.subject, description)
|
||||
def delete(%__MODULE__{} = graph, %Description{} = description, opts),
|
||||
do: do_delete(graph, description.subject, description, opts)
|
||||
|
||||
def delete(%__MODULE__{} = graph, %__MODULE__{} = input) do
|
||||
def delete(%__MODULE__{} = graph, %__MODULE__{} = input, opts) do
|
||||
Enum.reduce(input.descriptions, graph, fn {_, description}, graph ->
|
||||
delete(graph, description)
|
||||
delete(graph, description, opts)
|
||||
end)
|
||||
end
|
||||
|
||||
if Version.match?(System.version(), "~> 1.10") do
|
||||
def delete(%__MODULE__{} = graph, input)
|
||||
def delete(%__MODULE__{} = graph, input, opts)
|
||||
when is_list(input) or (is_map(input) and not is_struct(input)) do
|
||||
Enum.reduce(input, graph, &delete(&2, &1))
|
||||
Enum.reduce(input, graph, &delete(&2, &1, opts))
|
||||
end
|
||||
else
|
||||
def delete(_, %_{}), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
def delete(_, %_{}, _), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
|
||||
def delete(%__MODULE__{} = graph, input) when is_list(input) or is_map(input) do
|
||||
Enum.reduce(input, graph, &delete(&2, &1))
|
||||
def delete(%__MODULE__{} = graph, input, opts) when is_list(input) or is_map(input) do
|
||||
Enum.reduce(input, graph, &delete(&2, &1, opts))
|
||||
end
|
||||
end
|
||||
|
||||
defp do_delete(%__MODULE__{descriptions: descriptions} = graph, subject, input) do
|
||||
defp do_delete(%__MODULE__{descriptions: descriptions} = graph, subject, input, opts) do
|
||||
if description = descriptions[subject] do
|
||||
new_description = Description.delete(description, input)
|
||||
new_description = Description.delete(description, input, opts)
|
||||
|
||||
%__MODULE__{
|
||||
graph
|
||||
|
@ -792,42 +791,43 @@ defmodule RDF.Graph do
|
|||
@doc """
|
||||
Checks if the given `input` statements exist within `graph`.
|
||||
"""
|
||||
@spec include?(t, input) :: boolean
|
||||
def include?(graph, input)
|
||||
@spec include?(t, input, keyword) :: boolean
|
||||
def include?(graph, input, opts \\ [])
|
||||
|
||||
def include?(%__MODULE__{} = graph, {subject, _, _} = triple),
|
||||
do: do_include?(graph, coerce_subject(subject), triple)
|
||||
def include?(%__MODULE__{} = graph, {subject, _, _} = triple, opts),
|
||||
do: do_include?(graph, coerce_subject(subject), triple, opts)
|
||||
|
||||
def include?(graph, {subject, predicate, object, _}),
|
||||
do: include?(graph, {subject, predicate, object})
|
||||
def include?(graph, {subject, predicate, object, _}, opts),
|
||||
do: include?(graph, {subject, predicate, object}, opts)
|
||||
|
||||
def include?(%__MODULE__{} = graph, {subject, predications}),
|
||||
do: do_include?(graph, coerce_subject(subject), predications)
|
||||
def include?(%__MODULE__{} = graph, {subject, predications}, opts),
|
||||
do: do_include?(graph, coerce_subject(subject), predications, opts)
|
||||
|
||||
def include?(%__MODULE__{} = graph, %Description{subject: subject} = description),
|
||||
do: do_include?(graph, subject, description)
|
||||
def include?(%__MODULE__{} = graph, %Description{subject: subject} = description, opts),
|
||||
do: do_include?(graph, subject, description, opts)
|
||||
|
||||
def include?(graph, %__MODULE__{} = other_graph) do
|
||||
def include?(graph, %__MODULE__{} = other_graph, opts) do
|
||||
other_graph
|
||||
|> descriptions()
|
||||
|> Enum.all?(&include?(graph, &1))
|
||||
|> Enum.all?(&include?(graph, &1, opts))
|
||||
end
|
||||
|
||||
if Version.match?(System.version(), "~> 1.10") do
|
||||
def include?(graph, input) when is_list(input) or (is_map(input) and not is_struct(input)) do
|
||||
Enum.all?(input, &include?(graph, &1))
|
||||
def include?(graph, input, opts)
|
||||
when is_list(input) or (is_map(input) and not is_struct(input)) do
|
||||
Enum.all?(input, &include?(graph, &1, opts))
|
||||
end
|
||||
else
|
||||
def include?(_, %_{}), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
def include?(_, %_{}, _), do: raise(ArgumentError, "structs are not allowed as input")
|
||||
|
||||
def include?(graph, input) when is_list(input) or is_map(input) do
|
||||
Enum.all?(input, &include?(graph, &1))
|
||||
def include?(graph, input, opts) when is_list(input) or is_map(input) do
|
||||
Enum.all?(input, &include?(graph, &1, opts))
|
||||
end
|
||||
end
|
||||
|
||||
defp do_include?(%__MODULE__{descriptions: descriptions}, subject, input) do
|
||||
defp do_include?(%__MODULE__{descriptions: descriptions}, subject, input, opts) do
|
||||
if description = descriptions[subject] do
|
||||
Description.include?(description, input)
|
||||
Description.include?(description, input, opts)
|
||||
else
|
||||
false
|
||||
end
|
||||
|
|
|
@ -140,8 +140,8 @@ defmodule RDF.PrefixMap do
|
|||
and `namespace2` (the namespace for the prefix in the second prefix map).
|
||||
The value returned by the `conflict_resolver` function is used as the namespace
|
||||
for the prefix in the resulting prefix map.
|
||||
Non-`RDF.IRI` values will be tried to be converted to converted to `RDF.IRI`
|
||||
via `RDF.IRI.new` implicitly.
|
||||
Non-`RDF.IRI` values will be tried to be converted to `RDF.IRI`s via
|
||||
`RDF.IRI.new` implicitly.
|
||||
|
||||
The most common conflict resolution strategies on can be chosen directly with
|
||||
the following atoms:
|
||||
|
|
|
@ -13,6 +13,8 @@ defmodule RDF.PropertyMap do
|
|||
|
||||
def new(), do: %__MODULE__{}
|
||||
|
||||
def new(%__MODULE__{} = initial), do: initial
|
||||
|
||||
def new(initial) do
|
||||
{:ok, property_map} = new() |> add(initial)
|
||||
|
||||
|
|
|
@ -3,18 +3,14 @@ defmodule RDF.Quad do
|
|||
Helper functions for RDF quads.
|
||||
|
||||
A RDF Quad is represented as a plain Elixir tuple consisting of four valid
|
||||
RDF values for subject, predicate, object and a graph context.
|
||||
RDF values for subject, predicate, object and a graph name.
|
||||
"""
|
||||
|
||||
alias RDF.Statement
|
||||
alias RDF.{Statement, PropertyMap}
|
||||
|
||||
@type t ::
|
||||
{Statement.subject(), Statement.predicate(), Statement.object(), Statement.graph_name()}
|
||||
|
||||
@type coercible_t ::
|
||||
{Statement.coercible_subject(), Statement.coercible_predicate(),
|
||||
Statement.coercible_object(), Statement.coercible_graph_name()}
|
||||
|
||||
@type t_values :: {String.t(), String.t(), any, String.t()}
|
||||
|
||||
@doc """
|
||||
|
@ -28,21 +24,37 @@ defmodule RDF.Quad do
|
|||
|
||||
iex> RDF.Quad.new("http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph")
|
||||
{~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
|
||||
|
||||
iex> RDF.Quad.new(EX.S, EX.p, 42, EX.Graph)
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), RDF.iri("http://example.com/Graph")}
|
||||
|
||||
iex> RDF.Quad.new(EX.S, :p, 42, EX.Graph, RDF.PropertyMap.new(p: EX.p))
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), RDF.iri("http://example.com/Graph")}
|
||||
"""
|
||||
@spec new(
|
||||
Statement.coercible_subject(),
|
||||
Statement.coercible_predicate(),
|
||||
Statement.coercible_object(),
|
||||
Statement.coercible_graph_name()
|
||||
Statement.coercible_graph_name(),
|
||||
PropertyMap.t() | nil
|
||||
) :: t
|
||||
def new(subject, predicate, object, graph_context) do
|
||||
def new(subject, predicate, object, graph_name, property_map \\ nil)
|
||||
|
||||
def new(subject, predicate, object, graph_name, nil) do
|
||||
{
|
||||
Statement.coerce_subject(subject),
|
||||
Statement.coerce_predicate(predicate),
|
||||
Statement.coerce_object(object),
|
||||
Statement.coerce_graph_name(graph_context)
|
||||
Statement.coerce_graph_name(graph_name)
|
||||
}
|
||||
end
|
||||
|
||||
def new(subject, predicate, object, graph_name, %PropertyMap{} = property_map) do
|
||||
{
|
||||
Statement.coerce_subject(subject),
|
||||
Statement.coerce_predicate(predicate, property_map),
|
||||
Statement.coerce_object(object),
|
||||
Statement.coerce_graph_name(graph_name)
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -57,12 +69,26 @@ defmodule RDF.Quad do
|
|||
|
||||
iex> RDF.Quad.new {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"}
|
||||
{~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
|
||||
|
||||
iex> RDF.Quad.new {EX.S, EX.p, 42, EX.Graph}
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), RDF.iri("http://example.com/Graph")}
|
||||
|
||||
iex> RDF.Quad.new {EX.S, EX.p, 42}
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), nil}
|
||||
|
||||
iex> RDF.Quad.new {EX.S, :p, 42, EX.Graph}, RDF.PropertyMap.new(p: EX.p)
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), RDF.iri("http://example.com/Graph")}
|
||||
"""
|
||||
@spec new(coercible_t) :: t
|
||||
def new({subject, predicate, object, graph_context}),
|
||||
do: new(subject, predicate, object, graph_context)
|
||||
@spec new(Statement.coercible_t(), PropertyMap.t() | nil) :: t
|
||||
def new(statement, property_map \\ nil)
|
||||
|
||||
def new({subject, predicate, object, graph_name}, property_map) do
|
||||
new(subject, predicate, object, graph_name, property_map)
|
||||
end
|
||||
|
||||
def new({subject, predicate, object}, property_map) do
|
||||
new(subject, predicate, object, nil, property_map)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Returns a tuple of native Elixir values from a `RDF.Quad` of RDF terms.
|
||||
|
@ -96,12 +122,12 @@ defmodule RDF.Quad do
|
|||
@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_context}, mapping) do
|
||||
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_context_value <- mapping.({:graph_name, graph_context}) do
|
||||
{subject_value, predicate_value, object_value, graph_context_value}
|
||||
graph_name_value <- mapping.({:graph_name, graph_name}) do
|
||||
{subject_value, predicate_value, object_value, graph_name_value}
|
||||
else
|
||||
_ -> nil
|
||||
end
|
||||
|
@ -114,7 +140,7 @@ defmodule RDF.Quad do
|
|||
|
||||
The elements of a valid RDF quad must be RDF terms. On the subject
|
||||
position only IRIs and blank nodes allowed, while on the predicate and graph
|
||||
context position only IRIs allowed. The object position can be any RDF term.
|
||||
name position only IRIs allowed. The object position can be any RDF term.
|
||||
"""
|
||||
@spec valid?(t | any) :: boolean
|
||||
def valid?(tuple)
|
||||
|
|
|
@ -5,7 +5,7 @@ defmodule RDF.Statement do
|
|||
A RDF statement is either a `RDF.Triple` or a `RDF.Quad`.
|
||||
"""
|
||||
|
||||
alias RDF.{BlankNode, IRI, Literal, Quad, Term, Triple}
|
||||
alias RDF.{BlankNode, IRI, Literal, Quad, Term, Triple, PropertyMap}
|
||||
import RDF.Guards
|
||||
|
||||
@type subject :: IRI.t() | BlankNode.t()
|
||||
|
@ -22,7 +22,9 @@ defmodule RDF.Statement do
|
|||
@type term_mapping :: (qualified_term -> any | nil)
|
||||
|
||||
@type t :: Triple.t() | Quad.t()
|
||||
@type coercible_t :: Triple.coercible_t() | Quad.coercible_t()
|
||||
@type coercible_t ::
|
||||
{coercible_subject(), coercible_predicate(), coercible_object(), coercible_graph_name()}
|
||||
| {coercible_subject(), coercible_predicate(), coercible_object()}
|
||||
|
||||
@doc """
|
||||
Creates a `RDF.Statement` tuple with proper RDF values.
|
||||
|
@ -36,8 +38,7 @@ defmodule RDF.Statement do
|
|||
iex> RDF.Statement.coerce {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"}
|
||||
{~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42), ~I<http://example.com/Graph>}
|
||||
"""
|
||||
@spec coerce(Triple.coercible_t()) :: Triple.t()
|
||||
@spec coerce(Quad.coercible_t()) :: Quad.t()
|
||||
@spec coerce(coercible_t()) :: Triple.t() | Quad.t()
|
||||
def coerce(statement)
|
||||
def coerce({_, _, _} = triple), do: Triple.new(triple)
|
||||
def coerce({_, _, _, _} = quad), do: Quad.new(quad)
|
||||
|
@ -62,6 +63,16 @@ defmodule RDF.Statement do
|
|||
def coerce_predicate(iri) when maybe_ns_term(iri) or is_binary(iri), do: RDF.iri!(iri)
|
||||
def coerce_predicate(arg), do: raise(RDF.Triple.InvalidPredicateError, predicate: arg)
|
||||
|
||||
@doc false
|
||||
@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)
|
||||
end
|
||||
|
||||
def coerce_predicate(term, _), do: coerce_predicate(term)
|
||||
|
||||
@doc false
|
||||
@spec coerce_object(coercible_object) :: object
|
||||
def coerce_object(iri)
|
||||
|
|
|
@ -6,14 +6,10 @@ defmodule RDF.Triple do
|
|||
RDF values for subject, predicate and object.
|
||||
"""
|
||||
|
||||
alias RDF.Statement
|
||||
alias RDF.{Statement, PropertyMap}
|
||||
|
||||
@type t :: {Statement.subject(), Statement.predicate(), Statement.object()}
|
||||
|
||||
@type coercible_t ::
|
||||
{Statement.coercible_subject(), Statement.coercible_predicate(),
|
||||
Statement.coercible_object()}
|
||||
|
||||
@type t_values :: {String.t(), String.t(), any}
|
||||
|
||||
@doc """
|
||||
|
@ -27,15 +23,22 @@ defmodule RDF.Triple do
|
|||
|
||||
iex> RDF.Triple.new("http://example.com/S", "http://example.com/p", 42)
|
||||
{~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42)}
|
||||
|
||||
iex> RDF.Triple.new(EX.S, EX.p, 42)
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)}
|
||||
|
||||
iex> RDF.Triple.new(EX.S, :p, 42, RDF.PropertyMap.new(p: EX.p))
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)}
|
||||
"""
|
||||
@spec new(
|
||||
Statement.coercible_subject(),
|
||||
Statement.coercible_predicate(),
|
||||
Statement.coercible_object()
|
||||
Statement.coercible_object(),
|
||||
PropertyMap.t() | nil
|
||||
) :: t
|
||||
def new(subject, predicate, object) do
|
||||
def new(subject, predicate, object, property_map \\ nil)
|
||||
|
||||
def new(subject, predicate, object, nil) do
|
||||
{
|
||||
Statement.coerce_subject(subject),
|
||||
Statement.coerce_predicate(predicate),
|
||||
|
@ -43,6 +46,14 @@ defmodule RDF.Triple do
|
|||
}
|
||||
end
|
||||
|
||||
def new(subject, predicate, object, %PropertyMap{} = property_map) do
|
||||
{
|
||||
Statement.coerce_subject(subject),
|
||||
Statement.coerce_predicate(predicate, property_map),
|
||||
Statement.coerce_object(object)
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a `RDF.Triple` with proper RDF values.
|
||||
|
||||
|
@ -54,11 +65,24 @@ defmodule RDF.Triple do
|
|||
|
||||
iex> RDF.Triple.new {"http://example.com/S", "http://example.com/p", 42}
|
||||
{~I<http://example.com/S>, ~I<http://example.com/p>, RDF.literal(42)}
|
||||
|
||||
iex> RDF.Triple.new {EX.S, EX.p, 42}
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)}
|
||||
|
||||
iex> RDF.Triple.new {EX.S, EX.p, 42, EX.Graph}
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)}
|
||||
|
||||
iex> RDF.Triple.new {EX.S, :p, 42}, RDF.PropertyMap.new(p: EX.p)
|
||||
{RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)}
|
||||
"""
|
||||
@spec new(coercible_t) :: t
|
||||
def new({subject, predicate, object}), do: new(subject, predicate, object)
|
||||
@spec new(Statement.coercible_t(), PropertyMap.t() | nil) :: t
|
||||
def new(statement, property_map \\ nil)
|
||||
|
||||
def new({subject, predicate, object}, property_map),
|
||||
do: new(subject, predicate, object, property_map)
|
||||
|
||||
def new({subject, predicate, object, _}, property_map),
|
||||
do: new(subject, predicate, object, property_map)
|
||||
|
||||
@doc """
|
||||
Returns a tuple of native Elixir values from a `RDF.Triple` of RDF terms.
|
||||
|
|
|
@ -11,7 +11,7 @@ defmodule RDF.Test.Case do
|
|||
|
||||
using do
|
||||
quote do
|
||||
alias RDF.{Dataset, Graph, Description, IRI, XSD}
|
||||
alias RDF.{Dataset, Graph, Description, IRI, XSD, PropertyMap}
|
||||
alias unquote(__MODULE__).{EX, FOAF}
|
||||
|
||||
import RDF, only: [iri: 1, literal: 1, bnode: 1]
|
||||
|
|
|
@ -151,6 +151,11 @@ defmodule RDF.DatasetTest do
|
|||
)
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
ds = Dataset.new({EX.S, :p, EX.O}, context: [p: EX.p()])
|
||||
assert dataset_includes_statement?(ds, {EX.S, EX.p(), EX.O})
|
||||
end
|
||||
|
||||
@tag skip: "This case is currently not supported, since it's indistinguishable from Keywords"
|
||||
test "creating a dataset with a list of subject-predications pairs" do
|
||||
ds =
|
||||
|
@ -800,6 +805,54 @@ defmodule RDF.DatasetTest do
|
|||
assert dataset_includes_statement?(ds, {EX.S2, EX.p(), EX.O5, EX.Graph2})
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
context =
|
||||
PropertyMap.new(
|
||||
p1: EX.p1(),
|
||||
p2: EX.p2()
|
||||
)
|
||||
|
||||
assert Dataset.add(dataset(), {EX.Subject, :p, 42}, context: [p: EX.predicate()])
|
||||
|> dataset_includes_statement?({RDF.iri(EX.Subject), EX.predicate(), literal(42)})
|
||||
|
||||
assert Dataset.add(dataset(), {EX.Subject, :p, 42, EX.Graph}, context: %{p: EX.predicate()})
|
||||
|> dataset_includes_statement?(
|
||||
{RDF.iri(EX.Subject), EX.predicate(), literal(42), EX.Graph}
|
||||
)
|
||||
|
||||
g =
|
||||
Dataset.add(
|
||||
dataset(),
|
||||
[
|
||||
{EX.S1, :p1, EX.O1},
|
||||
{EX.S2, :p2, [EX.O21, EX.O22]}
|
||||
],
|
||||
context: context
|
||||
)
|
||||
|
||||
assert Dataset.statement_count(g) == 3
|
||||
assert dataset_includes_statement?(g, {EX.S1, EX.p1(), EX.O1})
|
||||
assert dataset_includes_statement?(g, {EX.S2, EX.p2(), EX.O21})
|
||||
assert dataset_includes_statement?(g, {EX.S2, EX.p2(), EX.O22})
|
||||
|
||||
g =
|
||||
Dataset.add(
|
||||
dataset(),
|
||||
[
|
||||
{EX.S1,
|
||||
[
|
||||
{:p1, EX.O1},
|
||||
%{p2: [EX.O2]}
|
||||
]}
|
||||
],
|
||||
context: context
|
||||
)
|
||||
|
||||
assert Dataset.statement_count(g) == 2
|
||||
assert dataset_includes_statement?(g, {EX.S1, EX.p1(), EX.O1})
|
||||
assert dataset_includes_statement?(g, {EX.S1, EX.p2(), EX.O2})
|
||||
end
|
||||
|
||||
test "duplicates are ignored" do
|
||||
ds = Dataset.add(dataset(), {EX.Subject, EX.predicate(), EX.Object, EX.GraphName})
|
||||
assert Dataset.add(ds, {EX.Subject, EX.predicate(), EX.Object, EX.GraphName}) == ds
|
||||
|
@ -1104,6 +1157,14 @@ defmodule RDF.DatasetTest do
|
|||
assert dataset_includes_statement?(ds, {EX.S2, EX.p2(), EX.O5})
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
ds =
|
||||
Dataset.new()
|
||||
|> Dataset.put({EX.S, :p, EX.O}, context: [p: EX.p()])
|
||||
|
||||
assert dataset_includes_statement?(ds, {EX.S, EX.p(), EX.O})
|
||||
end
|
||||
|
||||
test "simultaneous use of the different forms to address the default context" do
|
||||
ds =
|
||||
Dataset.put(dataset(), [
|
||||
|
@ -1283,6 +1344,14 @@ defmodule RDF.DatasetTest do
|
|||
assert dataset_includes_statement?(ds, {EX.S2, EX.p(), EX.O5})
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
ds =
|
||||
Dataset.new()
|
||||
|> Dataset.put_properties({EX.S, :p, EX.O}, context: [p: EX.p()])
|
||||
|
||||
assert dataset_includes_statement?(ds, {EX.S, EX.p(), EX.O})
|
||||
end
|
||||
|
||||
test "simultaneous use of the different forms to address the default context" do
|
||||
ds =
|
||||
Dataset.put_properties(dataset(), [
|
||||
|
@ -1469,6 +1538,13 @@ defmodule RDF.DatasetTest do
|
|||
assert Dataset.delete(dataset2, dataset1) == Dataset.new({EX.S2, EX.p2(), EX.O2, EX.Graph})
|
||||
end
|
||||
|
||||
test "with a context", %{dataset2: dataset2} do
|
||||
assert dataset2
|
||||
|> Dataset.delete(%{EX.S2 => %{p2: EX.O2}}, graph: EX.Graph, context: [p2: EX.p2()])
|
||||
|> Dataset.delete([{EX.S1, [p1: EX.O1]}], context: [p1: EX.p1()]) ==
|
||||
Dataset.new()
|
||||
end
|
||||
|
||||
test "structs are causing an error" do
|
||||
assert_raise struct_not_allowed_as_input_error(), fn ->
|
||||
Dataset.delete(dataset(), Date.utc_today())
|
||||
|
@ -1571,6 +1647,15 @@ defmodule RDF.DatasetTest do
|
|||
assert Dataset.include?(dataset, EX.p(EX.S2, EX.O2), graph: EX.Graph)
|
||||
assert Dataset.include?(dataset, Graph.new(EX.S1 |> EX.p(EX.O1)))
|
||||
assert Dataset.include?(dataset, dataset)
|
||||
|
||||
assert Dataset.include?(
|
||||
dataset,
|
||||
[
|
||||
{EX.S1, :p, EX.O1},
|
||||
{EX.S2, :p, EX.O2, EX.Graph}
|
||||
],
|
||||
context: [p: EX.p()]
|
||||
)
|
||||
end
|
||||
|
||||
test "structs are causing an error" do
|
||||
|
|
|
@ -55,6 +55,23 @@ defmodule RDF.DescriptionTest do
|
|||
desc = Description.new(EX.Subject, init: other_desc)
|
||||
assert description_of_subject(desc, iri(EX.Subject))
|
||||
assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object)})
|
||||
|
||||
desc =
|
||||
Description.new(
|
||||
EX.Subject,
|
||||
init: %{
|
||||
p1: EX.Object1,
|
||||
p2: EX.Object2
|
||||
},
|
||||
context: %{
|
||||
p1: EX.predicate1(),
|
||||
p2: EX.predicate2()
|
||||
}
|
||||
)
|
||||
|
||||
assert description_of_subject(desc, iri(EX.Subject))
|
||||
assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object1)})
|
||||
assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)})
|
||||
end
|
||||
|
||||
test "with an initializer function" do
|
||||
|
@ -233,6 +250,75 @@ defmodule RDF.DescriptionTest do
|
|||
assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object4)})
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
context =
|
||||
PropertyMap.new(
|
||||
p1: EX.p1(),
|
||||
p2: EX.p2()
|
||||
)
|
||||
|
||||
assert Description.add(description(), {iri(EX.Subject), :p, literal(42)},
|
||||
context: [p: EX.predicate()]
|
||||
)
|
||||
|> description_includes_predication({EX.predicate(), literal(42)})
|
||||
|
||||
assert Description.add(description(), {iri(EX.Subject), :p, literal(42), EX.Graph},
|
||||
context: %{p: EX.predicate()}
|
||||
)
|
||||
|> description_includes_predication({EX.predicate(), literal(42)})
|
||||
|
||||
desc =
|
||||
Description.add(
|
||||
description(),
|
||||
[
|
||||
p1: EX.O1,
|
||||
p2: [EX.O2, ~L"foo", "bar", 42]
|
||||
],
|
||||
context: context
|
||||
)
|
||||
|
||||
assert description_includes_predication(desc, {EX.p1(), iri(EX.O1)})
|
||||
assert description_includes_predication(desc, {EX.p2(), iri(EX.O2)})
|
||||
assert description_includes_predication(desc, {EX.p2(), ~L"foo"})
|
||||
assert description_includes_predication(desc, {EX.p2(), ~L"bar"})
|
||||
assert description_includes_predication(desc, {EX.p2(), RDF.literal(42)})
|
||||
|
||||
desc =
|
||||
Description.add(
|
||||
description(),
|
||||
%{
|
||||
p1: EX.Object1,
|
||||
p2: [EX.Object2, 42, bnode(:foo)]
|
||||
},
|
||||
context: context
|
||||
)
|
||||
|
||||
assert Description.count(desc) == 4
|
||||
assert description_includes_predication(desc, {EX.p1(), iri(EX.Object1)})
|
||||
assert description_includes_predication(desc, {EX.p2(), iri(EX.Object2)})
|
||||
assert description_includes_predication(desc, {EX.p2(), literal(42)})
|
||||
assert description_includes_predication(desc, {EX.p2(), bnode(:foo)})
|
||||
|
||||
desc =
|
||||
Description.add(
|
||||
description(),
|
||||
[
|
||||
{:p1, EX.Object1},
|
||||
{EX.Subject, :p2, EX.Object2},
|
||||
%{p2: EX.Object3},
|
||||
EX.predicate(EX.Other, EX.Object4)
|
||||
],
|
||||
context: context
|
||||
)
|
||||
|
||||
assert Description.count(desc) == 4
|
||||
assert description_of_subject(desc, iri(EX.Subject))
|
||||
assert description_includes_predication(desc, {EX.p1(), iri(EX.Object1)})
|
||||
assert description_includes_predication(desc, {EX.p2(), iri(EX.Object2)})
|
||||
assert description_includes_predication(desc, {EX.p2(), iri(EX.Object3)})
|
||||
assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object4)})
|
||||
end
|
||||
|
||||
test "triples with another subject are ignored" do
|
||||
assert empty_description(
|
||||
Description.add(description(), {EX.Other, EX.predicate(), iri(EX.Object)})
|
||||
|
@ -382,7 +468,6 @@ defmodule RDF.DescriptionTest do
|
|||
)
|
||||
|
||||
assert Description.count(desc) == 3
|
||||
|
||||
assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object4)})
|
||||
assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)})
|
||||
assert description_includes_predication(desc, {EX.predicate3(), iri(EX.Object3)})
|
||||
|
@ -397,6 +482,31 @@ defmodule RDF.DescriptionTest do
|
|||
) == desc
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
desc =
|
||||
Description.put(
|
||||
description(),
|
||||
[
|
||||
{:p1, EX.Object1},
|
||||
{EX.Subject, :p2, EX.Object2},
|
||||
%{p3: EX.Object3},
|
||||
EX.predicate(EX.Other, EX.Object4)
|
||||
],
|
||||
context: [
|
||||
p1: EX.p1(),
|
||||
p2: EX.p2(),
|
||||
p3: EX.p3()
|
||||
]
|
||||
)
|
||||
|
||||
assert Description.count(desc) == 4
|
||||
assert description_of_subject(desc, iri(EX.Subject))
|
||||
assert description_includes_predication(desc, {EX.p1(), iri(EX.Object1)})
|
||||
assert description_includes_predication(desc, {EX.p2(), iri(EX.Object2)})
|
||||
assert description_includes_predication(desc, {EX.p3(), iri(EX.Object3)})
|
||||
assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object4)})
|
||||
end
|
||||
|
||||
test "triples with another subject are ignored" do
|
||||
assert empty_description(
|
||||
Description.put(description(), {EX.Other, EX.predicate(), iri(EX.Object)})
|
||||
|
@ -529,6 +639,28 @@ defmodule RDF.DescriptionTest do
|
|||
) == Description.new(EX.S, init: {EX.S, EX.p1(), EX.O2})
|
||||
end
|
||||
|
||||
test "with a context", %{description3: description3} do
|
||||
desc =
|
||||
Description.delete(
|
||||
description3,
|
||||
[
|
||||
{:p1, EX.O1},
|
||||
{EX.S, :p2, EX.O3},
|
||||
%{p3: ~B<foo>},
|
||||
EX.p3(EX.S, ~L"bar")
|
||||
],
|
||||
context: [
|
||||
p1: EX.p1(),
|
||||
p2: EX.p2(),
|
||||
p3: EX.p3()
|
||||
]
|
||||
)
|
||||
|
||||
assert Description.count(desc) == 1
|
||||
assert description_of_subject(desc, iri(EX.S))
|
||||
assert description_includes_predication(desc, {EX.p1(), iri(EX.O2)})
|
||||
end
|
||||
|
||||
test "structs are causing an error" do
|
||||
assert_raise struct_not_allowed_as_input_error(), fn ->
|
||||
Description.delete(description(), Date.utc_today())
|
||||
|
@ -646,7 +778,7 @@ defmodule RDF.DescriptionTest do
|
|||
assert Enum.count(desc.predications) == 1
|
||||
end
|
||||
|
||||
describe "include?/2" do
|
||||
describe "include?/3" do
|
||||
test "valid cases" do
|
||||
desc =
|
||||
Description.new(EX.S,
|
||||
|
@ -672,6 +804,16 @@ defmodule RDF.DescriptionTest do
|
|||
refute Description.include?(desc, {EX.p4(), EX.O1})
|
||||
refute Description.include?(desc, {EX.p1(), EX.O3})
|
||||
refute Description.include?(desc, {EX.p1(), [EX.O1, EX.O3]})
|
||||
|
||||
assert Description.include?(
|
||||
desc,
|
||||
%{
|
||||
p1: [EX.O1, EX.O2],
|
||||
p2: EX.O3,
|
||||
p3: [~B<foo>, "bar"]
|
||||
},
|
||||
context: %{p1: EX.p1(), p2: EX.p2(), p3: EX.p3()}
|
||||
)
|
||||
end
|
||||
|
||||
test "structs are causing an error" do
|
||||
|
|
|
@ -123,6 +123,21 @@ defmodule RDF.GraphTest do
|
|||
assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object})
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
g =
|
||||
Graph.new(
|
||||
[
|
||||
{EX.Subject1, p1: EX.Object1},
|
||||
%{EX.Subject2 => %{p2: EX.Object2}}
|
||||
],
|
||||
context: %{p1: EX.predicate1(), p2: EX.predicate2()}
|
||||
)
|
||||
|
||||
assert unnamed_graph?(g)
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
|
||||
assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2})
|
||||
end
|
||||
|
||||
test "with prefixes" do
|
||||
assert Graph.new(prefixes: %{ex: EX}) ==
|
||||
%Graph{prefixes: PrefixMap.new(ex: EX)}
|
||||
|
@ -305,6 +320,7 @@ defmodule RDF.GraphTest do
|
|||
EX.Subject3 => %{EX.predicate3() => EX.Object3}
|
||||
})
|
||||
|
||||
assert Graph.triple_count(g) == 3
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2(), EX.Object2})
|
||||
assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3})
|
||||
|
@ -325,11 +341,13 @@ defmodule RDF.GraphTest do
|
|||
])
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 2
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2(), EX.Object2})
|
||||
|
||||
g = Graph.add(g, Description.new(EX.Subject1, init: {EX.predicate3(), EX.Object3}))
|
||||
|
||||
assert Graph.triple_count(g) == 3
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2(), EX.Object2})
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate3(), EX.Object3})
|
||||
|
@ -348,6 +366,7 @@ defmodule RDF.GraphTest do
|
|||
Description.new(EX.Subject1, init: {EX.predicate3(), EX.Object3})
|
||||
])
|
||||
|
||||
assert Graph.triple_count(g) == 3
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
|
||||
assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2})
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate3(), EX.Object3})
|
||||
|
@ -369,6 +388,7 @@ defmodule RDF.GraphTest do
|
|||
])
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 3
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
|
||||
assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2})
|
||||
assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3})
|
||||
|
@ -382,6 +402,7 @@ defmodule RDF.GraphTest do
|
|||
])
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 5
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1})
|
||||
assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object2})
|
||||
assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2})
|
||||
|
@ -422,6 +443,77 @@ defmodule RDF.GraphTest do
|
|||
assert graph.prefixes == PrefixMap.new(ex: EX)
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
context =
|
||||
PropertyMap.new(
|
||||
p1: EX.p1(),
|
||||
p2: EX.p2()
|
||||
)
|
||||
|
||||
assert Graph.add(graph(), {EX.Subject, :p, 42}, context: [p: EX.predicate()])
|
||||
|> graph_includes_statement?({RDF.iri(EX.Subject), EX.predicate(), literal(42)})
|
||||
|
||||
assert Graph.add(graph(), {EX.Subject, :p, 42, EX.Graph}, context: %{p: EX.predicate()})
|
||||
|> graph_includes_statement?({RDF.iri(EX.Subject), EX.predicate(), literal(42)})
|
||||
|
||||
g =
|
||||
Graph.add(
|
||||
graph(),
|
||||
[
|
||||
{EX.S1, :p1, EX.O1},
|
||||
{EX.S2, :p2, [EX.O21, EX.O22]}
|
||||
],
|
||||
context: context
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 3
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O1})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O21})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O22})
|
||||
|
||||
g =
|
||||
Graph.add(
|
||||
graph(),
|
||||
[
|
||||
{EX.S1,
|
||||
[
|
||||
{:p1, EX.O1},
|
||||
%{p2: [EX.O2]}
|
||||
]}
|
||||
],
|
||||
context: context
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 2
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O1})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p2(), EX.O2})
|
||||
|
||||
g =
|
||||
Graph.add(
|
||||
graph(),
|
||||
[
|
||||
%{EX.S1 => {:p1, EX.O1}},
|
||||
%{
|
||||
EX.S1 => %{p1: EX.O11},
|
||||
EX.S2 => %{p1: EX.O2}
|
||||
},
|
||||
{EX.S2, {:p2, EX.O2}},
|
||||
[{EX.S2, {:p2, EX.O21}}],
|
||||
EX.p2(EX.S2, EX.O22)
|
||||
],
|
||||
context: context
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 6
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O1})
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O11})
|
||||
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p1(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O21})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O22})
|
||||
end
|
||||
|
||||
test "non-coercible Triple elements are causing an error" do
|
||||
assert_raise RDF.IRI.InvalidError, fn ->
|
||||
Graph.add(graph(), {"not a IRI", EX.predicate(), iri(EX.Object)})
|
||||
|
@ -612,6 +704,24 @@ defmodule RDF.GraphTest do
|
|||
assert graph.base_iri == EX.base()
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.p1(), EX.O1}, {EX.S2, EX.p2(), EX.O2}])
|
||||
|> Graph.put(
|
||||
%{
|
||||
EX.S1 => [p1: EX.O2],
|
||||
EX.S2 => %{p1: EX.O2},
|
||||
EX.S3 => %{p3: EX.O3}
|
||||
},
|
||||
context: [p1: EX.p1(), p3: EX.p3()]
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 3
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p1(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S3, EX.p3(), EX.O3})
|
||||
end
|
||||
|
||||
test "structs are causing an error" do
|
||||
assert_raise struct_not_allowed_as_input_error(), fn ->
|
||||
Graph.put(graph(), Date.utc_today())
|
||||
|
@ -801,6 +911,25 @@ defmodule RDF.GraphTest do
|
|||
assert graph.base_iri == EX.base()
|
||||
end
|
||||
|
||||
test "with a context" do
|
||||
g =
|
||||
Graph.new([{EX.S1, EX.p1(), EX.O1}, {EX.S2, EX.p2(), EX.O2}])
|
||||
|> Graph.put_properties(
|
||||
%{
|
||||
EX.S1 => [p1: EX.O2],
|
||||
EX.S2 => %{p1: EX.O2},
|
||||
EX.S3 => %{p3: EX.O3}
|
||||
},
|
||||
context: [p1: EX.p1(), p3: EX.p3()]
|
||||
)
|
||||
|
||||
assert Graph.triple_count(g) == 4
|
||||
assert graph_includes_statement?(g, {EX.S1, EX.p1(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p1(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S2, EX.p2(), EX.O2})
|
||||
assert graph_includes_statement?(g, {EX.S3, EX.p3(), EX.O3})
|
||||
end
|
||||
|
||||
test "structs are causing an error" do
|
||||
assert_raise struct_not_allowed_as_input_error(), fn ->
|
||||
Graph.put_properties(graph(), Date.utc_today())
|
||||
|
@ -812,7 +941,7 @@ defmodule RDF.GraphTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "delete/2" do
|
||||
describe "delete/3" do
|
||||
setup do
|
||||
{:ok,
|
||||
graph1: Graph.new({EX.S, EX.p(), EX.O}),
|
||||
|
@ -912,6 +1041,18 @@ defmodule RDF.GraphTest do
|
|||
) == Graph.new({EX.S3, EX.p3(), ~L"bar"})
|
||||
end
|
||||
|
||||
test "with a context", %{graph2: graph2} do
|
||||
assert Graph.delete(
|
||||
graph2,
|
||||
[
|
||||
%{EX.S => %{p: EX.O1}},
|
||||
%{EX.S => {:p, [EX.O2]}}
|
||||
],
|
||||
context: [p: EX.p()]
|
||||
) ==
|
||||
Graph.new(name: EX.Graph)
|
||||
end
|
||||
|
||||
test "preserves the name and prefixes" do
|
||||
graph =
|
||||
Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.GraphName, prefixes: %{ex: EX})
|
||||
|
@ -1051,7 +1192,7 @@ defmodule RDF.GraphTest do
|
|||
assert Enum.count(graph.descriptions) == 1
|
||||
end
|
||||
|
||||
describe "include?/2" do
|
||||
describe "include?/3" do
|
||||
test "valid cases" do
|
||||
graph =
|
||||
Graph.new([
|
||||
|
@ -1077,6 +1218,15 @@ defmodule RDF.GraphTest do
|
|||
assert Graph.include?(graph, EX.S1 |> EX.p(EX.O1))
|
||||
assert Graph.include?(graph, Graph.new(EX.S1 |> EX.p(EX.O1)))
|
||||
assert Graph.include?(graph, graph)
|
||||
|
||||
assert Graph.include?(
|
||||
graph,
|
||||
[
|
||||
%{EX.S1 => %{p: EX.O1}},
|
||||
%{EX.S2 => {:p, [EX.O2]}}
|
||||
],
|
||||
context: [p: EX.p()]
|
||||
)
|
||||
end
|
||||
|
||||
test "structs are causing an error" do
|
||||
|
|
Loading…
Reference in a new issue