We are really glad to announce the release candidate for Ecto 2.0 has been released. The upcoming Ecto version packs many goodies:
- We have migrated to DBConnection, which considerably improves the performance of how Ecto manages connections to the database as a whole. Improved pool management, faster encoding/decoding, support for prepared queries and more;
-
The effective deprecation of
Ecto.Model
in favor of a more data-oriented approach. With Ecto 2.0, we want developers to focus on using Ecto as a tool instead of being responsible for your domain design; -
Support for
many_to_many
associations and a more flexible approach to associations in general, including parallel preloading of associations; -
Introduction of a new SQL sandbox that allows developers to run tests that rely on the database concurrently;
-
Support for subqueries, composite primary keys,
insert_all
(alongsideupdate_all
anddelete_all
) and more.
There are many more features, bug fixes, and improvements. There are also backwards incompatible changes (hence the 2.0 version). We recommend you to check the CHANGELOG for more information.
We recommend developers to give the release candidate a try. There are only a couple of improvements left before the final release. In case you encounter an unexpected behaviour, please open up an issue report.
This release supports both MySQL (mariaex) and PostgreSQL (postgrex) adapters.
Using Ecto 2.0.0-rc with Phoenix
This release candidate introduced some backwards incompatible changes for those using Ecto in their Phoenix projects. We summarize those changes below:
- The first step is to update the
Phoenix.Ecto
dependency to3.0.0-rc
(which depends onecto
2.0.0-rc
) in yourmix.exs
:{:phoenix_ecto, "~> 3.0.0-rc"}
- Ecto 2.0 now requires an explicit
:ecto_repos
configuration for running tasks likeecto.migrate
and others. Open up yourconfig/config.exs
and add:config :my_app, ecto_repos: [MyApp.Repo]
- We also recommend developers to move the creation and migration of their test databases to aliases. First, remove the following lines from your
test/test_helper.exs
:Mix.Task.run "ecto.create", ~w(-r <%= application_module %>.Repo --quiet) Mix.Task.run "ecto.migrate", ~w(-r <%= application_module %>.Repo --quiet)
And now add the following entry to
defp aliases
in yourmix.exs
file:"test": ["ecto.create --quiet", "ecto.migrate", "test"]
- Ecto also changed how it stores changeset in errors. If you are using gettext, you will need to update your
errors.po
files as well as yourerror_helper.ex
view -
Phoenix projects by default use transactions in the test environment. Ecto 2.0 replaces the test transactions API by the new SQL sandbox. In your
test/test_helper.exs
, replace the following:Ecto.Adapters.SQL.begin_test_transaction(MyApp.Repo)
by
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, :manual)
Then, in each
test/support/*_case.ex
file, replace:unless tags[:async] do Ecto.Adapters.SQL.restart_test_transaction(MyApp.Repo, []) end
by
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo) unless tags[:async] do Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()}) end
That’s it! You can check the pull request that migrates Phoenix generators to Ecto 2.0-rc for a detailed list of changes.
Before we move on, let’s explore exactly what the sandbox changes mean in the next section.
Concurrent transactional tests
In previous versions, Ecto would keep a single connection to the database during tests and wrap the connection inside a transaction for every test. Ecto 2.0 introduces a sandbox mechanism where every test gets its own connection to the database, all of them wrapped in a transaction. Such allows tests to run concurrently by passing async: true
to use MyApp.ConnCase
(and similar) even if they rely on the database.
Let’s further explore the changes we did above. In your test helper, you should now see:
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, :manual)
This command sets the sandbox to manual mode, meaning any Elixir process must explicitly check a database connection out before performing any database operation. If you open up test/support/conn_case.ex
, you should see:
setup tags do
:ok = Ecto.Adapters.SQL.Sandbox.checkout(MyApp.Repo)
unless tags[:async] do
Ecto.Adapters.SQL.Sandbox.mode(MyApp.Repo, {:shared, self()})
end
:ok
end
The second line in the snippet above does exactly that: it checks a connection out and wraps it inside a transaction. After the connection is checked out, it belongs exclusively to the current test process.
If you enabled async: true
in your test case, its tests will run concurrently with tests from other test cases, each of them using its own and isolated database connection.
If the test is not asynchronous (:async
was not set to true), we will execute the unless
block in setup
and share the connection we just checked out with all other processes, effectively falling back to the mechanism we had in Ecto 1.0.
The SQL Sandbox provides other options for managing your concurrent tests and you can learn more about them in the Ecto documentation.
We recommend developers to enable their concurrent tests and enjoy even faster test suites. When doing so, have the following in mind:
- MySQL does not support concurrent tests. Unfortunately, MySQL will run into deadlocks when different connections try to write to the same table inside transactions and those transactions are rolled back;
-
When testing your models, controllers, and views, most of the tests should be able to run concurrently as is, except if they are interacting with other Elixir processes in your application (see example in the next bullet);
-
On the other hand, your channel tests require the collaboration between two processes: the test process and the channel process itself. If the channel process is accessing the database, you will need to allow explicitly it to use a database connection. See the
Ecto.Adapters.SQL.Sandbox.allow/2
function; -
Finally, tools for writing acceptance tests like Hound and Wallaby also support concurrent tests. You can find more information about doing so in the Phoenix.Ecto README.
Summing up
We are really excited about Ecto 2.0. By focusing on Ecto as a tool instead of an abstraction layer, we expect developers to have a simpler and a more light-weight mechanism for interacting with databases.
In the upcoming weeks, we will publish a series of blog posts that focuses on the new features and perspectives brought by Ecto 2.0. Meanwhile, don’t forget to read the CHANGELOG for the full list of changes.
Congratulations, and many thanks to you and the rest of the Ecto team and contributors!
Great news, this is getting better and better!
Congrats on the release. We’ve been using Ecto 2.0 beta for a few weeks now and the new changes have been very welcome. Keep up the great work!