You must require Ecto.Query before invoking the macro Ecto.Query.from

So I wanted to write a single line script to execute quickly in the console, using Ecto.Query.

Hence I wanted to write:

   MyApp.Repo.update_all(
     Ecto.Query.from(d in MyApp.MyModel,
     where: is_nil(d.my_attribute)),
     set: [my_attribute: "My value"]
   )

But I get this error:

** (CompileError) iex:3: you must require Ecto.Query before invoking the macro Ecto.Query.from/2

Can anyone explain this to me being still phoenix noob?

How can I achieve my single line command?

To me using require or import has global implications, it adds context and make the subsequent code less predictable, so it is not desired unless within a file (where scope is controlled). Am I being too limited?

Public functions in modules are globally available, but macros are not.

import Ecto.Query, only: [from: 2]
#or
require Ecto.Query
1 Like

Import has lexical implications, not global implications. The distinction is that import only makes a change within the current lexical scope. You can do it within a function for example and then it only makes the functions / macros available for that function:

def foo() do
  import Ecto.Query
  from() # works
end

def bar() do
  from() # won't work
end

Even if you put require or import in a bare ex or exs file, the scope is always limited to that file. It is impossible in Elixir to add a global import, you don’t have to worry about polluting global scope.

require is also lexically scoped, but unlike import it doesn’t change the context. Macros are a powerful tool, but they can also introduce complexity, so using require helps indicate that the module being required has macros that this module will be using. It also helps the compiler generate the correct compilation graph, since it tells the compiler that it needs to ensure Ecto.Query is compiled before attempting to compile your module.

There are perfectly good arguments for not using import if you like keeping your function / macro calls very explicit. require though is not optional, which is fine since it doesn’t change any of the code that comes afterward anyway.

4 Likes

Thanks for clarification!

Is there a way I could know from is a macro and not a function? I am still unclear over the difference between the two but I reckon on that, I need to make deeper researches.

A function is simply something that takes an Elixir value, and returns an elixir value. When you have add(num1, num2 + 2), whenever add/2 is called it receives whatever value num1 and num2 + 2 to have at the point of evaluation.

A macro is a function that receives code itself as an argument, and is allowed to return code that replaces what was there before. So for example if you have some_macro(a + b) it doesn’t receive the value of a + b, but rather a representation of the code a + b. It’s then allowed to return different code. This process happens not at runtime, but when the context of the some_macro call is compiled.

This is how, for example, the Ecto.Query macros can prevent SQL injection at compile time. If you try to do something dangerous like: from u in User, where: fragment("name = #{name}") you get ** (Ecto.Query.CompileError) to prevent SQL injection attacks. This is because the from macro receives the actual code we pass to it, and can look through that code for dangerous behavior.

Not by looking at a call. This is part of the purpose of the require Foo. It helps clue us into the fact that calls involving the Foo module may involve macros.

3 Likes

So many thanks for those explanations!

Have a great day

1 Like

Thank you. This, at last, clarified why require is called require. That was really bugging me :slight_smile: