abdulsattar

abdulsattar

How do Ecto bindings work?

How does this work?

query = from u in "users",
          where: u.age > 18,
          select: u.name

I get that from is a macro, which essentially takes two arguments:

query = from(u in "users",
          [where: u.age > 18,
          select: u.name])

which makes it more mysterious. u in "users" what does it do? The keyword list has u.age, where does the u come from? How is throwing u not defined exception?

The macro based syntax is also suprising:

"users"
|> where([u], u.age > 18)
|> select([:name])

How does where([u], u.age > 18) not fail with u not defined?

Marked As Solved

minhajuddin

minhajuddin

A macro doesn’t execute the code passed in, It gets an AST of the code and it can then do whatever it wants. I haven’t looked at how Ecto actually does this, I am assuming that it gets a hold of the AST and transforms it into a SQL query based on the operators that are being used and then it executes the code. One way to inspect it is by looking at the struct that was returned:

iex(7)> q = from(u in User, where: u.id == 3, order_by: [asc: :id]) |> Map.from_struct
%{
  assocs: [],
  distinct: nil,
  from: {"users", UA.Accounts.User},
  group_bys: [],
  havings: [],
  joins: [],
  limit: nil,
  lock: nil,
  offset: nil,
  order_bys: [
    %Ecto.Query.QueryExpr{
      expr: [asc: {{:., [], [{:&, [], [0]}, :id]}, [], []}],
      file: "iex",
      line: 7,
      params: []
    }
  ],
  prefix: nil,
  preloads: [],
  select: nil,
  sources: nil,
  updates: [],
  wheres: [
    %Ecto.Query.BooleanExpr{
      expr: {:==, [],
       [
         {{:., [], [{:&, [], [0]}, :id]}, [], []},
         %Ecto.Query.Tagged{tag: nil, type: {0, :id}, value: 3}
       ]},
      file: "iex",
      line: 7,
      op: :and,
      params: []
    }
  ]
}

Here is an example that should give you more clarith around macros, the expression 1 + 2 is never evaluated:

defmodule M do
  defmacro add({:+, _, [op1, op2]}) do
    quote do
      "Add #{unquote(op1)} and #{unquote(op2)} yourself!"
    end
  end
end

defmodule Test do
  def test do
    require M
    M.add(1 + 3)
  end
end

Test.test() |> IO.puts
# => Add 1 and 3 yourself!

Also Liked

LostKobrakai

LostKobrakai

Elixir is not directly using what you wrote for the ecto query, but ecto transforms the AST of your code into something that makes sense to elixir.

Where Next?

Popular in Questions Top

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
sergio
In Ruby, I can go: User.find_by(email: "foobar@email.com").update(email: "hello@email.com") How can I do something similar in Elixir? ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
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
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New

Other popular topics Top

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
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
johnnyicon
Hi all, I’ve just started learning Elixir and Phoenix Framework, so please pardon my n00bness at this stage. I’m trying to use Postgres...
New
vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement