lib/sparql/algebra/expression/minus.ex

defmodule SPARQL.Algebra.Minus do
  defstruct [:expr1, :expr2]

  alias __MODULE__
  alias SPARQL.Algebra.Expression
  alias SPARQL.Query.Result.SolutionMapping


  def result_set(query_result1, query_result2) do
    %SPARQL.Query.Result{
      variables: query_result1.variables,
      results: minus(query_result1.results, query_result2.results)
    }
  end

  def minus(results1, results2) do
    # TODO: optimization: Assuming the variables of all solutions are the same, just look at the first solution to determine if variables are disjoint
    Enum.filter results1, fn result1 ->
      Enum.all? results2, fn result2 ->
        !SolutionMapping.compatible?(result1, result2) ||
          SolutionMapping.disjoint?(result1, result2)
      end
    end
  end

  defimpl Expression do
    def evaluate(minus, data, execution) do
      Minus.result_set(
        Expression.evaluate(minus.expr1, data, execution),
        Expression.evaluate(minus.expr2, data, execution))
    end

    def variables(minus) do
      Expression.variables(minus.expr1)
    end
  end
end