Acceso a Datos con Elixir (Ecto)

Cristian Rengifo
6 min readMar 8, 2019

--

Ecto es un conjunto de herramientas para el mapeo de datos y un lenguaje integrado de consulta para Elixir.

Ecto se compone de 4 componentes principales:

  • Ecto.Repo: Define los repositorios que son envolturas alrededor de un almacén de datos. Usándolo, podemos insertar, eliminar y consultar un repositorio.
  • Ecto.Schema: Se utilizan para asignar cualquier fuente de datos a una estructura de Elixir (mapearlos).
  • Ecto.Changeset: Proporcionan una forma de filtrar, así como un mecanismo para rastrear y validar los cambios antes de que se apliquen a los datos.
  • Ecto.Query: Permite realizar consultas SQL similar a Linq para recuperar información de un repositorio. Las consultas en Ecto son seguras, evitan problemas comunes como la Inyección de SQL.

Ya con las bases sobre qué es Ecto, nos vamos manos a la obra y realizamos la parte práctica.

En este momento deben tener Instalado:

Para empezar, se debe crear una nueva aplicación con un supervisor, para ello usamos Mix.

$ mix new cars --sup

Esto creará un directorio con los archivos iniciales del proyecto:

--sup crea un árbol de supervisores que mantendrá la conexión a la base de datos.

Con el proyecto ya creado ingresamos al directorio cars con cd cars y abrimos nuestro editor de código de preferencia, en mi caso Vs Code. Una vez abierto el proyecto abrimos el archivo mix.exs y hacemos el siguiente cambio.

defp deps do
[
{:ecto_sql, “~> 3.0”},
{:postgrex, “>= 0.14.1”}
]
end

Lo que se hizo fue agregar al proyecto las dependencias Ecto y el driver de postgres para Elixir. El paso siguiente es obtener las dependencias con:

$ mix deps.get

Repositorio (Ecto.Repo):

El paso a seguir es crear un repositorio. Debemos configurar nuestra base de datos ingresando el comando:

$ mix ecto.gen.repo -r Cars.Repo
Nuevo Repositorio

El comando se encarga de actualizar el archivo config/config.exs con los datos básicos para la configuración de la base de datos.

El repositorio se genera en lib/cars/repo.ex

Módulo necesario para el acceso a la base de datos

Una nota muy importante mostrada en consola es que debemos agregar el nuevo repositorio al supervisor. Para eso editamos lib/cars/application.ex.

Para finalizar la configuración, agregamos en config/config.exs, la siguiente línea.

config :cars, ecto_repos: [Cars.Repo]

Ahora hemos configurado la aplicación para que pueda hacer consultas a nuestra base de datos. Posteriormente creamos una base de datos, agregamos una tabla y luego realizamos algunas consultas.

Para crear la base de datos ingresamos en la consola el comando

$ mix ecto.create
Ecto se encarga de crear la db

Ya creada la base de datos el paso siguiente es crear las tablas que consultaremos.

Migraciones (Ecto.Migration)

Para crear migraciones se usa el siguiente comando:

$ mix ecto.gen.migration brand
$ mix ecto.gen.migration car

Este comando generará un nuevo archivo de migración en la ruta priv/repo/migrations, que está vacío de forma predeterminada, entonces como ingresamos dos comandos tenemos dos archivos, brand y car:

Migración para Brand
Migración para car

Para ejecutar las migraciones y crear las tablas brand y car ejecutaremos el siguiente comando:

$ mix ecto.migrate

Ya con eso las tablas car y brand son creadas por Ecto en nuestra base de datos.

Esquema (Ecto.schema)

El esquema es una representación de Elixir de los datos de nuestra base de datos. Los esquemas se asocian comúnmente con una tabla de base de datos, sin embargo, también pueden asociarse con una vista de base de datos.

Vamos a crear el esquema dentro de la aplicación en lib/cars/car.exy se debe hacer lo mismo para brand:

car schema

Esto define el esquema de la base de datos a la que se asigna. En este caso, le estamos diciendo a Ecto que el esquema Cars.car se asigna a la tabla car en la base de datos.

Ya tenemos a disposición el esquema, si ingresamos a una sesión de iex con iex -S mix podemos hacer lo siguiente:

$ brand = %Cars.Brand{}

Con esto el sistema nos devuelve la estructura de brand, pero también podemos setear valores

$ brand = %Cars.Brand{description: “Chevrolet”}

También es posible insertar un nuevo registro en la base de datos

$ Cars.Repo.insert(brand)

Ya Ecto se encargó de realizar el insert donde se asigna el id 1 a Chevrolet, como vemos una inserción exitosa nos retorna una tupla. Hacemos lo mismo para car.

car insert

Es posible validar los cambios antes de guardarlos en la base de datos, por ejemplo podemos requerir que todos los campos sean obligatorios, para eso está Ecto.Changeset, vamos a validar que todos los campos de car sean obligatorios, para lograrlo ingresamos a nuestro esquema car y agregamos:

changeset para car

Lo que hace es que toma un car, la primera función se encarga de decirle al changeset que parámetros se pueden usar; la siguiente línea donde llamamos validate_required indica que valores son requeridos. Probamos el changeset:

El changeset nos informa que model no puede estar vacía.

También es posible hacer múltiples insert de la siguiente manera:

Ahora que tenemos la tabla poblada hagamos consultas:

Para obtener un solo registro de la tabla:

$ Cars.Car |> Ecto.Query.first

Ese comando nos crearía un Ecto.Query pero si queremos ejecutar la consulta:

$ Cars.Car |> Ecto.Query.first |> Cars.Repo.one

Si queremos retornar todos los registros:

$ Cars.Car |> Cars.Repo.all

Si queremos obtener un registro por ID:

$ Cars.Car |> Cars.Repo.get(1)

Si queremos un registro basado en un atributo específico usamos:

$ Cars.Car |> Cars.Repo.get_by(brand_id: 2)

Y filtramos resultados con:

$ Cars.Car |> Ecto.Query.where(model: 2018) |> Cars.Repo.all

Para Actualizar registros requerimos que primero se obtenga un registro:

$ car = Cars.Car |> Ecto.Query.first |> Cars.Repo.one

Una vez se obtiene el registro, construimos un changeset, así Ecto sabe qué esta cambiando

$ changeset = Cars.Car.changeset(car, %{model: 2017})

y para informar a la db el cambio ejecutamos:

$ Cars.Repo.update(changeset)

Con eso se logró Actualizar el registro, es el mismo procedimiento para realizar un delete, se obtiene el registro y luego se realiza

$ Cars.Repo.delete(car)

Con esto se ha revisado parte de lo que podemos hacer con Ecto en Elixir. Falta mucho más por aprender y lo podemos revisar en la documentación de Ecto. En las próximas publicaciones avanzaremos más con Elixir.

El código se encuentra en el siguiente repositorio

https://github.com/ingcrengifo/cars

--

--

Cristian Rengifo

Software Developer #ASPNET, #WebApi, #MVC, #Angular, #Informix4GL and learning #Elixir