lib/macro/generators.ex

defmodule FunctionGenerator do
  @doc false
  defmacro new(env) do
    for func <- [:to_tsquery, :phraseto_tsquery, :plainto_tsquery, :websearch_to_tsquery] do
      quote do
        @doc """
        Creates a new Vectorex instance which can be used to build a full text search query
        """
        def new(unquote(func), param) do
          %unquote(env.module){params: [param], function: unquote(func)}
        end
      end
    end
  end

  @doc false
  defmacro new_subquery(env) do
    quote do
      @doc """
      Creates a new Vectorex.Subquery instance 
      """
      def new(param) do
        %unquote(env.module){params: [param]}
      end
    end
  end

  @doc false
  defmacro operators(env) do
    for operator <- [:not, :and, :or, :followed_by] do
      quote do
        @doc """
        Adds a clause to the builder using #{unquote(operator)}
        If the operator is supported by the text search control, the parameter is applied
        to the builder. If not the parameter is ignored.
        """
        @spec unquote(:"ts_#{operator}")(
                vector :: unquote(env.module).t(),
                params :: [String.t()] | String.t()
              ) :: unquote(env.module).t()
        def unquote(:"ts_#{operator}")(%unquote(env.module){} = vector, params)
            when is_list(params) do
          Enum.reduce(params, vector, fn param, acc ->
            unquote(:"ts_#{operator}")(acc, param)
          end)
        end

        def unquote(:"ts_#{operator}")(%unquote(env.module){} = vector, param) do
          append_param = fn ->
            %{vector | params: [{unquote(operator), param} | vector.params]}
          end

          case param do
            param = %Vectorex.Subquery{} ->
              append_param.()

            param when is_binary(param) ->
              append_param.()

            _ ->
              vector
          end
        end
      end
    end
  end
end