Wednesday, June 15, 2016

An Introduction to Elixir’s Ecto Library

Elixir is a modern, dynamic, functional programming language used to build highly distributed and fault-tolerant applications. Ecto is its main library for working with databases, providing us with tools to interact with databases under a common API, version the database alongside our application, and handle data processing within our application.

This article takes a quick look at the major aspects of the Ecto library. Basic knowledge of Elixir and Mix are assumed.

The Application

We'll be building a very simple application from scratch that will store and retrieve notes for us. By doing this, we'll look through each of Ecto's four main components: repos, schemas, changesets, and queries.

Creating a new application

Let's start by generating a new Mix application:

mix new notex --sup

The --sup flag generates some additional boilerplate code that's required for an OTP application. This application needs to have a supervision tree, because Ecto needs it (more on this in a minute).

Setting up the dependencies

Now, let's update our mix.exs file with some application dependencies. For this, we're going to want to specify Ecto and one of its adapters. I've chosen to use MySQL for this, so we'll need to specify the Mariaex library (Ecto supports a number of databases).

Update the application/0 function in the mix.exs file with the following:

def application do
  [applications: [:logger, :ecto, :mariaex],
   mod: {Notex, []}]
end

And update deps/0 with the following:

defp deps do
  [{:ecto, "~> 1.1.5"},
   {:mariaex, "~> 0.6.0"}]
end

Now fetch the dependencies with mix deps.get.

Next, we need to integrate these dependencies into our application. This will involve creating a new wrapper module for an Ecto repository, updating our application's supervision tree to start and supervise that new module, and configuring the adapter's connection information.

Let's firstly start by defining a Notex.Repo module at lib/notex/repo.ex with the following code:

defmodule Notex.Repo do
  use Ecto.Repo, otp_app: :notex
end

The location of this module (lib/app_name/repo.ex) is conventional. Any time we use a mix ecto command, it will default to looking for the defined repository at AppName.Repo. We can place it elsewhere, but it will be at the inconvenience of having to specify its location using the -r (or --repo) flag.

The above Notex.Repo module enables us to work with databases using Ecto. It does this by firstly injecting functions from Ecto's Repo module (that provide the database querying API) and by secondly naming our OTP application as :notex.

An Ecto repository provides us with a common interface to interact with an underlying database (which is decided upon by the adapter being used). As such, whilst Ecto uses the terminology repo, it does not follow the repository design pattern, since it's a wrapper around a database, not a table.

Now that we have defined the Notex.Repo module, we must now add this to our supervision tree in the Notex module (at lib/notex.ex). Update the start/2 function with the following:

def start(_type, _args) do
  import Supervisor.Spec, warn: false

  children = [
    supervisor(Notex.Repo, []),
  ]

  opts = [strategy: :one_for_one, name: Notex.Supervisor]
  Supervisor.start_link(children, opts)
end

We've added the Notex.Repo module as a child supervisor (since it is itself a supervising OTP app). This means that it will be supervised by our OTP application, and our application will be responsible for starting it upon application startup.

Each connection created with Ecto uses a separate process (where the process is pulled from a process pool using a library called Poolboy). This is done so that our queries can execute concurrently, as well as being resilient from failures (e.g. timeouts). Our application therefore requires OTP, because Ecto has its own processes that need supervising (including a supervision tree supervising a pool of database connections). This can be seen using Erlang's Observer library, which enables us to visualize the processes in an application.

Let's take a quick look at this. Start up our application in Elixir's interactive shell and then start the observer:

iex -S mix

iex(1)> :observer.start
:ok

Navigating to the Application tab, we can see the application's processes, including which ones are the supervisors:

Process tree

But that's as far down the rabbit hole we'll be going with respect to processes and OTP in this article. They will be covered in greater detail in later articles to come.

After having added the repo to our worker processes to be supervised, we need lastly to configure the adapter so that it can communicate with our database. Place the following code at the end of the config/config.exs file (updating the details as necessary):

config :notex, Notex.Repo,
  adapter: Ecto.Adapters.MySQL,
  database: "notex",
  username: "root",
  password: "root",
  hostname: "localhost"

Here, we specify the name of our OTP application (:notex) and the name of our freshly defined module (Notex.Repo) for enabling communication with the database. The other configure options should be pretty self-explanatory.

Ecto actually provides us with a shortcut for setting up the above Repo module as a mix task: mix ecto.gen.repo. This generates the repository module for us and updates the config.exs file with some basic configuration (the Repo module still needs to be manually added to the supervision tree though). I avoided using it here predominantly for didactic reasons of showing how to set up Ecto manually (that, and the fact that the repo generator assumes you're using Postgres, so we would have had to update the adapter in the config anyway).

Continue reading %An Introduction to Elixir’s Ecto Library%


by Thomas Punt via SitePoint

No comments:

Post a Comment