lib/sparql/algebra/expression/filter.ex

defmodule SPARQL.Algebra.Filter do
  defstruct [:filters, :expr]

  alias SPARQL.Algebra.Expression
  alias RDF.XSD

  def result_set(%SPARQL.Query.Result{results: results} = result, filters, data, execution) do
    %SPARQL.Query.Result{result |
      results: Enum.filter(results, &(apply?(&1, filters, data, execution)))
    }
  end

  def apply?(solution, filters, data, execution) do
    filters
    |> Stream.map(fn function_call ->
         Expression.evaluate(function_call, %{solution: solution, data: data}, execution)
       end)
    |> Stream.map(&(RDF.XSD.Boolean.ebv/1))
    |> conjunction()
  end

  defp conjunction(function_call_results) do
    Enum.all? function_call_results, fn
      %RDF.Literal{literal: %XSD.Boolean{value: true}} -> true
      _ -> false
    end
  end


  defimpl Expression do
    def evaluate(filter, data, execution) do
      Expression.evaluate(filter.expr, data, execution)
      |> SPARQL.Algebra.Filter.result_set(filter.filters, data, execution)
    end

    # TODO: Are variables of filters taken into consideration?
    # TODO: What happens if variables are used, which are not part of the expression?
    def variables(filter) do
      Expression.variables(filter.expr)
    end
  end
end