Add path query builder

This commit is contained in:
Marcel Otto 2020-06-12 02:53:29 +02:00
parent b6aafccc7d
commit 8d68e925ad
2 changed files with 67 additions and 0 deletions

View file

@ -144,4 +144,35 @@ defmodule RDF.Query.Builder do
defp literal(%Literal{} = literal), do: literal
defp literal(value), do: Literal.coerce(value)
def path(query, opts \\ [])
def path(query, _) when is_list(query) and length(query) < 3 do
{:error, %RDF.Query.InvalidError{
message: "Invalid path expression: must have at least three elements"}
}
end
def path([subject | rest], opts) do
path_pattern(subject, rest, [], 0, Keyword.get(opts, :with_elements, false))
|> bgp()
end
def path!(query, opts \\ []) do
case path(query, opts) do
{:ok, bgp} -> bgp
{:error, error} -> raise error
end
end
defp path_pattern(subject, [predicate, object], triple_patterns, _, _) do
[{subject, predicate, object} | triple_patterns]
|> Enum.reverse()
end
defp path_pattern(subject, [predicate | rest], triple_patterns, count, with_elements) do
object = if with_elements, do: :"el#{count}?", else: RDF.bnode(count)
path_pattern(object, rest, [{subject, predicate, object} | triple_patterns], count + 1, with_elements)
end
end

View file

@ -150,4 +150,40 @@ defmodule RDF.Query.BuilderTest do
bgp [{EX.s, EX.p, EX.o}]
end
end
describe "path/2" do
test "element count == 3" do
assert Builder.path([EX.s, EX.p, EX.o]) == bgp [{EX.s, EX.p, EX.o}]
assert Builder.path([:s?, :p?, :o?]) == bgp [{:s, :p, :o}]
end
test "element count > 3" do
assert Builder.path([EX.s, EX.p1, EX.p2, EX.o]) ==
bgp [
{EX.s, EX.p1, RDF.bnode("0")},
{RDF.bnode("0"), EX.p2, EX.o},
]
assert Builder.path([:s?, :p1?, :p2?, :o?]) ==
bgp [
{:s, :p1, RDF.bnode("0")},
{RDF.bnode("0"), :p2, :o},
]
end
test "element count < 3" do
assert {:error, %RDF.Query.InvalidError{}} = Builder.path([EX.s, EX.p])
assert {:error, %RDF.Query.InvalidError{}} = Builder.path([EX.s])
assert {:error, %RDF.Query.InvalidError{}} = Builder.path([])
end
test "with_elements: true" do
assert Builder.path([EX.s, EX.p1, EX.p2, :o?], with_elements: true) ==
bgp [
{EX.s, EX.p1, :el0},
{:el0, EX.p2, :o},
]
end
end
end