Using a macro to select in an Ecto query

Hello there,

I am running into some macro issues when using Ecto.Query. I want to define my actual select function in a macro in order to reuse it later.

However, the code does not compile if the macro resides in a required module instead of the module actually doing the query:

defmodule A do
  defmacro name_of(e) do
    quote do
      %{name_of: unquote(e).name}
    end
  end
end

defmodule AQuery do
  require A
  import Ecto.Query

  # (Ecto.Query.CompileError) `A.name_of(e)` is not a valid query expression. 
  # If you want to invoke A.name_of/1 in a query, make sure that the module A 
  # is required and that name_of/1 is a macro
  def query_test(), do: Repo.all(from e in Employee, select: A.name_of(e))
  # Compiles & works
  def fun_test(), do: A.name_of(%{name: "Hello World"})
end

defmodule BQuery do
  import Ecto.Query

  defmacro description_of(e) do
    quote do
      %{description_of: unquote(e).description}
    end
  end

  # Compiles & works
  def query_test(), do: Repo.all(from e in Employee, select: description_of(e))
  # Compiles & works
  def fun_test(), do: description_of(%{description: "Hello there"})
end

I also tried various combinations of trying to pin e and/or the result of A.name_of/1, without success.

What did I do wrong to make AQuery.query_test/0 work?

Thank you for your time!

$ elixir -v
Erlang/OTP 23 [erts-11.1.4] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Elixir 1.11.3 (compiled with Erlang/OTP 23)
$ cat mix.exs | grep ecto_sql -C 3
  defp deps do
    [
      {:phoenix_pubsub, "~> 2.0"},
      {:ecto_sql, "~> 3.4"},
      {:postgrex, ">= 0.0.0"},
      {:jason, "~> 1.0"},
    ]
1 Like