dimitarvp

dimitarvp

Can a defguard definition match against a struct?

Hello,
Is it possible to check if an argument to a guard is a particular structure?

Context: I am trying to have a defguard definition that checks if something is an Ecto query – which means it can either be a module (e.g. atom) or it can be an %Ecto.Query{}. But I cannot seem to find a way to do it via defguard.

defmodule A do
  defguard is_query(q) when is_atom(q) or ... # <- what do we put here?
end

Tried with match?(%Ecto.Query{}, q) but that did not compile.

Something I am missing?

Marked As Solved

msimonborg

msimonborg

The simpler way to do this now is defguard is_query(a) when is_struct(a, Ecto.Query) using Kernel.is_struct/2, which was introduced after this thread was last active. PR #9470

As for your question, I am not 100% sure, but if what you have created is an Ecto.Query struct, it will match

Also Liked

idi527

idi527

As for your actual question:

defguard is_query(a) when is_map(a) and :erlang.map_get(:__struct__, a) == Ecto.Query
dimitarvp

dimitarvp

Ha, I like this a lot. Thanks for pointing it out.

wojtekmach

wojtekmach

Hex Core Team

It is impossible to do in a defguard. I think it is possible, with big caveats so maybe actually impossible too, with a defmacro. If the protocol is consolidated, you can grab the list of modules implementing it. So if your protocol is consolidated by the time you call your guard, which generally may not necessarily be the case, that should work. Here’s a sketch:

defmodule Macros do
  defmacro is_impl(term, protocol) do
    protocol = Macro.expand(protocol, __ENV__)

    impls =
      case protocol.__protocol__(:impls) do
        {:consolidated, impls} ->
          impls

        :not_consolidated ->
          raise "#{inspect(protocol)} is not consolidated"
      end

    quote do
      unquote(term).__struct__ in unquote(impls)
    end
  end
end

defmodule Foo do
  import Macros

  def f(enumerable) when is_impl(enumerable, Enumerable) do
    Enum.to_list(enumerable)
  end
end

besides the caveat around consolidation time, in the list of impls we have things like Atom, Integer, …, Any, and they all would have to be handled too.

So yeah, not worth it. :slight_smile:

Where Next?

Popular in Questions Top

tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
Tee
can someone please explain to me how Enum.reduce works with maps
New
chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 47849 226
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New

We're in Beta

About us Mission Statement