lib/sparql/query/query.ex

defmodule SPARQL.Query do
  @moduledoc """
  A structure for SPARQL queries.
  """

  defstruct [
    :base,
    :prefixes,
    :form,

    :expr,

    :query_string, # This might be only temporary until we have a functionally complete SPARQL language decoder and encoder
  ]

  alias __MODULE__

  @type t :: module

  @type forms :: :select | :construct | :describe | :ask


  @doc """
  Creates a `SPARQL.Query` struct.

  See `translate/2` for more information about default prefixes, all of which
  applies also to this function.
  """
  def new(query, options \\ [])

  def new(%Query{} = query, _options), do: query
  def new(query, options) when is_binary(query), do: translate(query, options)


  @doc """
  Creates a `SPARQL.Query` struct from a SPARQL language string.

  By default the configured `RDF.default_prefixes/0` will be automatically
  defined for the query, so that you can use these prefixes without having them
  defined manually in your query.
  You can overwrite these default prefixes and define another set of prefixes
  with the `default_prefixes` option.
  If you don't want to use default prefixes for the given query you
  can pass `nil` or an empty map for the `default_prefixes` option.

  If you don't want to use default prefixes at all, just don't configure any and
  set the `rdf` configuration flag `use_standard_prefixes` to `false`.
  See the [API documentation of RDF.ex](https://hexdocs.pm/rdf/RDF.html) for
  for more information about `RDF.default_prefixes/0` and `RDF.standard_prefixes/0`
  and how to configure them.
  """
  def translate(string, options \\ []) do
    with prefixes = (
           options
           |> Keyword.get(:default_prefixes, :default_prefixes)
           |> prefixes()
           |> encode_prefixes()
         ),
         {:ok, query} <-
           SPARQL.Language.Decoder.decode(prefixes <> "\n" <> string, options)
    do
      query
    end
  end

  defp prefixes(nil),               do: RDF.PrefixMap.new()
  defp prefixes(:default_prefixes), do: RDF.default_prefixes()
  defp prefixes(prefixes),          do: RDF.PrefixMap.new(prefixes)

  defp encode_prefixes(prefixes) do
    prefixes
    |> Stream.map(fn {prefix, iri} ->
         "PREFIX #{to_string(prefix)}: <#{to_string(iri)}>"
       end)
    |> Enum.join("\n")
  end

  defimpl String.Chars do
    def to_string(query) do
      query.query_string
    end
  end
end