How to do a macro that return another macro?

Hello ^^, I’m creating a API with Absinthe, I’m having many arguments that are being duplicated again and again, so I would like to implement a macro that calls that argument that they have all in common, for example change this:

    field :person, :person do
      arg(:slug, non_null(:string))

      arg(
        :language,
        :query_language,
        description: "A large description",
        default_value: :en
      )
    end

    field :company, :company do
      arg(:slug, non_null(:string))

      arg(
        :language,
        :query_language,
        description: "A large description",
        default_value: :en
      )
    end

to something like this:

    field :person, :person do
      arg(:slug, non_null(:string))

      get_language_argument()
    end

    field :company, :company do
      arg(:slug, non_null(:string))

      get_language_argument()
    end

So the get_language_argument(), return the arg macro, is that possible?

Greetings ^^/

Have you tried it?

defmacro get_language_argument do
  arg(
    :language,
    :query_language,
    description: "A large description",
    default_value: :en
  )
end

Should just work… But why do you need a macro? Why not just a function for get_language_argument?

Yeah I already tried it, but I get a compilation error

** (Absinthe.Schema.Notation.Error) Invalid schema notation: `arg` must only be used within `directive`, `field`
    lib/absinthe/schema/notation.ex:1463: Absinthe.Schema.Notation.do_recordable!/4
    expanding macro: Absinthe.Schema.Notation.arg/3
    lib/okami/schema.ex:176: Okami.Schema.get_language_argument/0
    (elixir) lib/kernel/parallel_compiler.ex:198: anonymous fn/4 in Kernel.ParallelCompiler.spawn_workers/6

Oh well yeah, there is no need for a macro if a function will work ^^’

What you want is to return AST that contains the arg macro you’re trying to inject.

defmacro get_language_argument do
  quote do
    arg(
      :language,
      :query_language,
      description: "A large description",
      default_value: :en
    )
  end
end

As far as the implied use case goes, unless it’s very common to request different fields in different languages I would consider setting a more global language flag in the context and just using that, instead of specifying it on every field.

Oh… Stupid me… forgot the quoteing… That happens when one tries to answer from a computer that has no elixir availbe and is in a hurry…