Macro: After compilation hook does not define functions in module

Hi

I am trying to add some general functions that can be shared across models by invoking

defmodule MyModel do
  use TPR.Model
  ...
end

My code:

defmodule TPR.Model do
  @moduledoc """
  
  """

  defmacro __using__(_opts) do
    quote do
      @after_compile __MODULE__

      use Ecto.Schema
      import Ecto.Changeset
      import Ectonum

      alias Ecto.Changeset

      @spec apply_non_persisted_changes(Changeset.t) :: {:ok, struct} | {:error, Changeset.t}
      def apply_non_persisted_changes(%Ecto.Changeset{valid?: true} = changeset), do: {:ok, apply_changes(changeset)}
      def apply_non_persisted_changes(%Ecto.Changeset{valid?: false} = changeset), do: {:error, changeset}

      defmacro __after_compile__(__env, _bytecode) do
        IO.inspect "asdaddsa!! #{__MODULE__}"
        quote do
          alias Ecto.Changeset
          import Ecto.Changeset

          IO.inspect "axxxx"

          @doc """
          Invokes `changeset/2` function in module and applies non-persisted changes using apply_non_persisted_changes/1
          """
          @spec build(map) :: t
          def build(params) do
            %__MODULE__{}
            |> changeset(params)
            |> apply_non_persisted_changes
          end

          @doc """
          Same as `build/1`, but raises an exception on failed validation
          """
          @spec build!(map) :: t
          def build!(params) do
            {:ok, event} = build(params)
            event
          end
        end
      end 
    end
  end
end

I have moved the helper function definitions to the __after_compile__ hook, as they depend on an Ecto schema having been defined in the module. This, to my understanding, is only the case after the initial compilation

For some reason the build/1 function does not get defined in the modules using TPR.Model, even though IO.inspect logs as expected.

Any ideas?

The module has already been compiled, you can’t inject anything anymore in @after_compile, you have to use @before_compile for last minute updates.

I’m not sure though, if you already have access to your required data in that case.

Using @before_compile ends up throwing Module X is not available

I can’t see any occurences of X in your code…

Sorry that was just a placeholder.

I moved the @before_compile hook to the end of the module and now it works