0
votes

I'm going through a Phoenix Liveview book and I came across this line:

|> where([d], d.user_id == ^user.id)

I'm trying to understand this syntax. I tried looking up the Elixir Guards but this isn't one of them. What is the [d] here? Is this some sort of an anonymous function?

Here is the function this was used in:

  def for_user(query \\ base(), user) do
    query
    |> where([d], d.user_id == ^user.id)
  end
2

2 Answers

2
votes

where is a macro defined by ecto. That's why to use it you need to import Ecto.Query, although in many cases you don't see that, because you have a use MyApp.Schema or something like that, which already includes the import. You can see the docs here: Ecto.Query.where docs.

The [d] is how the macro handles giving a name to the record(s) to be used in the where clause. You can change the name to anything, while changing the condition at the same time:

query
|> where([a_particular_record], a_particular_record.user_id == ^user.id)

Note that the macro also overrides what ^ means - inside the macro it means "inject this value from outside of the macro", which is why you need to use it before user.id.

1
votes

where is a macro that accepts a query as the first argument and returns a query so it can be used in pipelines. Piping many wheres results in combining them with AND. If you want to combine the where clauses with OR, you can use the or_where macro.

So, the following code:

query
|> where([user], user.id == ^user.id)
|> where([user], user.name == ^user.name)

will generate an SQL query that looks something like this:

WHERE user.id = 1 AND user.name = 'somename'

The second argument is a list of the so called bindings. In the example above, the user is a binding. Bindings work a lot like table aliases in SQL and effectively gives you a variable for referring to your table throughout your query (This description is taken from the great Programming Ecto which gives deep insight on how Ecto works and how to use it). The bindings list can contain more than one element in case the query contains joins. When using joins, the bindings should be matched in the order they are specified.

from(user in User)
|> join(:inner, [user], user_settings in assoc(u, :user_settings))
|> where([_user, us], where: us.role == "admin")

The bindings variable names can differ but they point to the same thing. In the example above, the user settings in join are bound to the user_settings variable, but in the where clause they are bound to the us variable.

Named bindings are also possible and they can solve some problems that the non-named bindings cannot, but they are not being described here. More for them can be found in the Ecto Documentation.

The last argument in the where macro is an expression that must evaluate to a boolean value. This expression contains the actual where clauses you want to write.