# Pattern match structure field

I’d like to implement a generic helper method that would work this way:

``````      def is_active(query \\ __MODULE__)
def is_active(query) when :is_active in __MODULE__.__schema__(:fields) do
where([q], q.is_active == true)
end
def is_active(query), do: query
``````

But it doesn’t work as I can’t pattern match `__MODULE__.__schema__`. Any solution to write this?

``````%__MODULE__{}.__schema__(:fields)
``````

UPDATE: I am completely wrong, I need a

1 Like

No, not really, as you cannot call remote functions at compile time for module you are compiling. However why would you define something like that? I assume that this is generated by macro. Maybe DB views would be something more readable (depending on the context).

Do you have to use pattern matching here? Why not just go with a simple `if`?

``````def is_active(query \\ __MODULE__) do
if :is_active in __MODULE__.__schema__(:fields) do
where(query, [q], q.is_active)
else
query
end
end
``````

You can not call remote functions in guards, as @hauleth wrote, because it happens in compile time. `__MODULE__.__schema__/1` is a remote function. Just use `cond` (or `if`):

``````def is_active(query \\ __MODULE__) do
cond do
:is_active in __MODULE__.__schema__(:fields) -> where(query, [q], q.is_active == true)
true -> query
end
end
``````

Assuming this function is being defined by a macro and you don’t mind very slightly touching ecto internals, you could branch at compile time instead of runtime. You could check a module attribute directly and conditionally define the function, but your schemas would have to call your macro after defining all the fields. To get around that, I’d use @before_compile in your macro.

``````# in your main macro
@before_compile MyApp.IsActive
``````

Then define another macro that will get called for the module before it’s compiled.

``````defmodule MyApp.IsActive do
def __before_compile__(%{module: module}) do
if {:is_active, :boolean} in Module.get_attribute(module, :ecto_fields, []) do
quote do
def is_active(query) do
require Ecto.Query # if you aren't importing in main macro
Ecto.Query.where(query, [q], q.is_active == true)
end
end
else
quote do
def is_active(query) do
query
end
end
end
end
end
``````