SlideShare una empresa de Scribd logo
1 de 30
Descargar para leer sin conexión
Capa de Persistencia
con Ecto
Rafael Gutiérrez, @abaddon_gtz
Julio 23, 2016
@ElixirLangMx
Ecto
● Framework de persistencia para Elixir (hecho en Elixir)
● Diseñado para bases de datos relacionales
● Ideas de LINQ de .NET y ActiveRecord de Rails
● Wrapper de la base de datos
● Lenguaje de consulta integrado (language integrated
query - LIQ) !!
○ DSL
LINQ & Ecto & SQL
# Elixir
from c in Customer,
where: c.city == “Mexico”,
select: c.company_name
// C#
from c in db.Customers
where c.City == “Mexico”
select c.CompanyName
-- SQL
SELECTcompany_name
FROM customer
WHERE city = ‘Mexico’
Beneficios de un LIQ
● Metadatos
● Validación de sintaxis en tiempo de compilación
● Tipos
● Seguridad
● Composición
Componentes de Ecto
● Ecto.Repo
● Ecto.Schema
● Ecto.Changeset
● Ecto.Query
Caso de Estudio
Administrar las propuestas de Workshops
Ecto.Repo
● Wrapper de la base de datos
● Via el Repo, creamos, consultamos, borramos y
actualizamos los datos
● Usa un Adapter para comunicarse a la BD
Crear el proyecto con mix
● > mix new wsp_app --sup
● --sup para generar una aplicación OTP con árbol de
supervisión
● Ecto.Repo corre bajo un árbol de supervisión
Dependencias
# mix.exs
defp deps do
[{:postgrex, ">= 0.0.0"},
{:ecto, "~> 2.0.0"}]
end
# mix.exs
def application do
[applications: [:logger, :ecto, :postgrex],
mod: {WspApp, []}]
end
Repositorio y árbol de supervisión
# Nuevo archivo /lib/wsp_app/repo.ex
defmodule WspApp.Repo do
use Ecto.Repo, otp_app: :wsp_app
End
# Agregar el repo al árbol de supervisión /lib/wsp_app.ex
def start(_type, _args) do
import Supervisor.Spec, warn: false
children = [supervisor(WspApp.Repo, [])]
opts = [strategy: :one_for_one, name: WspApp.Supervisor]
Supervisor.start_link(children, opts)
end
Adapter
# Configurar el Adapter /config/config.exs
config :wsp_app, WspApp.Repo,
adapter: Ecto.Adapters.Postgres,
database: "ws_proposal_app_dev",
username: "postgres",
password: "",
hostname: "localhost"
# pool_size: 20
# desde Ecto 2
config :wsp_app, ecto_repos: [WspApp.Repo]
Ecto.Schema
● Mapea la fuente de datos a un struct de Elixir
● Usado para mapear la tabla a datos de Elixir
Migration - workshop_proposals
# > mix ecto.gen.migration create_workshop_proposals_table
# /priv/repo/migrations/
defmodule WspApp.Repo.Migrations.CreateWorkshopProposalsTable do
use Ecto.Migration
def change do
create table(:workshop_proposals) do
add :title, :text
add :description, :text
add :instructor_email, :text
add :tentative_date, :date
timestamps
end
end
end
Migration - votes
# > mix ecto.gen.migration create_votes_table
# /priv/repo/migrations/
defmodule WspApp.Repo.Migrations.CreateVotesTable do
use Ecto.Migration
def change do
create table(:votes) do
add :email, :text
add :workshop_proposal_id,
references(:workshop_proposals, [on_delete: :delete_all, on_update: :update_all])
timestamps
end
end
end
Migration - unique index para votes
# > mix ecto.gen.migration create_unique_vote_constraint
# /priv/repo/migrations/
defmodule WspApp.Repo.Migrations.CreateUniqueVoteConstraint do
use Ecto.Migration
def change do
create unique_index(:votes, [:email, :workshop_proposal_id])
end
end
Modelo - WorkshopProposal
# /lib/wsp_app/workshop_proposal.ex
defmodule WspApp.WorkshopProposal do
use Ecto.Schema
schema "workshop_proposals" do
field :title, :string
field :description, :string
field :instructor_email, :string
field :tentative_date, Ecto.Date
has_many :votes, WspApp.Vote
timestamps
end
end
Modelo - Vote
# /lib/wsp_app/vote.ex
defmodule WspApp.Vote do
use Ecto.Schema
import Ecto.Changeset
schema "votes" do
field :email, :string
belongs_to :workshop_proposal, WspApp.WorkshopProposal, foreign_key: :workshop_proposal_id
timestamps
end
end
Ecto.Changeset
● Filtran y hacen ‘cast’ de parametros externos.
● Provee mecanismos para dar seguimiento (tracking) y
validación de cambios.
WorkshopProposal Changeset v1
# /lib/wsp_app/workshop_proposal.ex
defmodule WspApp.WorkshopProposal do
use Ecto.Schema
import Ecto.Changeset
# ... schema
def changeset(workshop_proposal, params  %{}) do
workshop_proposal
|> cast(params, [:title, :description, :instructor_email, :tentative_date])
|> validate_required([:title, :instructor_email, :tentative_date])
end
end
WorkshopProposal Changeset v2
def changeset(workshop_proposal, params  %{}) do
workshop_proposal
|> cast(params, [:title, :description, :instructor_email, :tentative_date])
|> validate_required([:title, :instructor_email, :tentative_date])
|> validate_format(:instructor_email, ~r/@/)
|> validate_change(:tentative_date, fn(:tentative_date, tentative_date) ->
case Ecto.Date.compare(tentative_date, Ecto.Date.from_erl(:erlang.date())) do
:lt -> [tentative_date: "cannot be less than today"]
:gt -> []
:eq -> []
end
end)
end
Vote Changeset
# /lib/wsp_app/vote.ex
defmodule WspApp.Vote do
use Ecto.Schema
import Ecto.Changeset
# ...
def changeset(vote, params  %{}) do
vote
|> cast(params, [:email, :workshop_proposal_id])
|> validate_required([:email, :workshop_proposal_id])
|> validate_format(:email, ~r/@/)
end
end
Ecto.Changeset Struct
● Algunos campos son:
○ valid? - si el changeset es válido
○ data - la fuente de datos
○ changes - los cambios aplicados
○ errors - los errores después de las validaciones
Ecto.Query
● Consultas SQL escritas en Elixir
● Son seguras porque evitan problemas como SQL Injection
● Son “armables”
Consultas sencillas
import Ecto.Query
# SELECT * FROM workshop_proposal
WspApp.Repo.all(from w in WspApp.WorkshopProposal)
# SELECT id, title, instructor_email FROM workshop_proposal
WspApp.Repo.all(from w in WspApp.WorkshopProposal,
select: [w.id, w.title, w.instructor_email])
# SELECT * from workshop_proposal WHERE instructor_email = 'rgutierrez@nearsoft.com'
WspApp.Repo.all(from w in WspApp.WorkshopProposal,
where: w.instructor_email == "rgutierrez@nearsof.com")
Interpolacion y ‘Casting’
import Ecto.Query
date = Ecto.Date.cast!("2016-09-10")
WspApp.Repo.all(from w in WspApp.WorkshopProposal, where: w.tentative_date > ^date)
email = "rgutierrez@nearsoft.com"
WspApp.Repo.all(from w in WspApp.WorkshopProposal, where: w.instructor_email == ^email)
# Error: ** (Ecto.QueryError) iex:7: value `"0"` cannot be dumped to type :id.
WspApp.Repo.all(from w in WspApp.WorkshopProposal, where: w.id > "0")
Composicion
query = from w in WspApp.WorkshopProposal,
where: w.tentative_date > ^Ecto.Date.cast!("2016-09-10")
WspApp.Repo.all(query)
WspApp.Repo.all(from w in query, select: w.title)
WspApp.Repo.all(from w in query,
select: {w.title, w.instructor_email},
where: w.instructor_email not in ["rgutierrez@nearsoft.com"])
Paginación
WspApp.Repo.all(from w in WspApp.WorkshopProposal,
limit: 10,
offset: 0)
WspApp.Repo.all(from w in WspApp.WorkshopProposal,
limit: 10,
offset: 10)
Operadores de Agregación y Joins
WspApp.Repo.all(from w in WspApp.WorkshopProposal,
join: v in WspApp.Vote, on: v.workshop_proposal_id == w.id,
where: v.workshop_proposal_id == w.id,
select: {w.title, count(v.id)},
group_by: w.title)
# gracias a la asociación
WspApp.Repo.all(from w in WspApp.WorkshopProposal,
join: v in WspApp.Vote,
where: v.workshop_proposal_id == w.id,
select: {w.title, count(v.id)},
group_by: w.title)
● count, avg, sum, min, max, group_by, having, order_by
Fragments
● Cuando se requiere usar funciones/operaciones
específicas del manejador de base de datos.
from p in Post,
where: is_nil(p.published_at) and
fragment("downcase(?)", p.title) == ^title
startTime = Ecto.DateTime.cast!({{2016, 11, 11}, {18, 00, 00}})
endTime = Ecto.DateTime.cast!({{2016, 11, 11}, {20, 00, 00}})
from c in Workshop,
where: fragment("(?, ?) OVERLAPS (?, ?)",
c.start, c.end, type(^startTime, Ecto.DateTime), type(^endTime, Ecto.DateTime))
Gracias!!!
Q&A

Más contenido relacionado

Destacado

Presentación 5 diapositivas
Presentación 5 diapositivasPresentación 5 diapositivas
Presentación 5 diapositivasteresa35
 
Series 16 -Attachment 2 -Momin Chetamani -English
Series 16  -Attachment 2 -Momin Chetamani -EnglishSeries 16  -Attachment 2 -Momin Chetamani -English
Series 16 -Attachment 2 -Momin Chetamani -EnglishSatpanth Dharm
 
Born to be studentpreneur
Born to be studentpreneurBorn to be studentpreneur
Born to be studentpreneurArry Rahmawan
 
Thor associates connecting brand[1]
Thor associates connecting brand[1]Thor associates connecting brand[1]
Thor associates connecting brand[1]THOR associates
 
Power fabri 2
Power fabri 2Power fabri 2
Power fabri 2tecdeinfo
 
Jika al quran bisa bicara
Jika al quran bisa bicaraJika al quran bisa bicara
Jika al quran bisa bicaraArry Rahmawan
 
Pipvtr policy brief 6
Pipvtr policy brief 6Pipvtr policy brief 6
Pipvtr policy brief 6GenPeace
 
Pharma sages cancer research plot for children
Pharma sages cancer research plot for childrenPharma sages cancer research plot for children
Pharma sages cancer research plot for childrenPharmaSages
 
GE 13 Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letter
GE 13  Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letterGE 13  Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letter
GE 13 Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letterSatpanth Dharm
 
130221 alpro event21_feb13_changing consumer behaviour
130221 alpro event21_feb13_changing consumer behaviour130221 alpro event21_feb13_changing consumer behaviour
130221 alpro event21_feb13_changing consumer behaviourKatrien Barrat
 
CerdasMulia Ramadhan - Training Ramadhan Pesantren Al-Munawaroh
CerdasMulia Ramadhan - Training Ramadhan Pesantren Al-MunawarohCerdasMulia Ramadhan - Training Ramadhan Pesantren Al-Munawaroh
CerdasMulia Ramadhan - Training Ramadhan Pesantren Al-MunawarohArry Rahmawan
 
Series 40 - Satya prakash v2 -History of Pirana Satpanth -Gujarati Book
Series 40 - Satya prakash  v2 -History of Pirana Satpanth -Gujarati Book Series 40 - Satya prakash  v2 -History of Pirana Satpanth -Gujarati Book
Series 40 - Satya prakash v2 -History of Pirana Satpanth -Gujarati Book Satpanth Dharm
 

Destacado (15)

Presentación 5 diapositivas
Presentación 5 diapositivasPresentación 5 diapositivas
Presentación 5 diapositivas
 
Series 16 -Attachment 2 -Momin Chetamani -English
Series 16  -Attachment 2 -Momin Chetamani -EnglishSeries 16  -Attachment 2 -Momin Chetamani -English
Series 16 -Attachment 2 -Momin Chetamani -English
 
Born to be studentpreneur
Born to be studentpreneurBorn to be studentpreneur
Born to be studentpreneur
 
Thor associates connecting brand[1]
Thor associates connecting brand[1]Thor associates connecting brand[1]
Thor associates connecting brand[1]
 
Power fabri 2
Power fabri 2Power fabri 2
Power fabri 2
 
A04n50 claudia feres
A04n50 claudia feresA04n50 claudia feres
A04n50 claudia feres
 
Jika al quran bisa bicara
Jika al quran bisa bicaraJika al quran bisa bicara
Jika al quran bisa bicara
 
Sorting Objects (Math)
Sorting Objects (Math)Sorting Objects (Math)
Sorting Objects (Math)
 
Pipvtr policy brief 6
Pipvtr policy brief 6Pipvtr policy brief 6
Pipvtr policy brief 6
 
Pharma sages cancer research plot for children
Pharma sages cancer research plot for childrenPharma sages cancer research plot for children
Pharma sages cancer research plot for children
 
GE 13 Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letter
GE 13  Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letterGE 13  Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letter
GE 13 Sanatan Dharm Jagruti's reply to Avichaldas maharaj's letter
 
130221 alpro event21_feb13_changing consumer behaviour
130221 alpro event21_feb13_changing consumer behaviour130221 alpro event21_feb13_changing consumer behaviour
130221 alpro event21_feb13_changing consumer behaviour
 
CerdasMulia Ramadhan - Training Ramadhan Pesantren Al-Munawaroh
CerdasMulia Ramadhan - Training Ramadhan Pesantren Al-MunawarohCerdasMulia Ramadhan - Training Ramadhan Pesantren Al-Munawaroh
CerdasMulia Ramadhan - Training Ramadhan Pesantren Al-Munawaroh
 
Series 40 - Satya prakash v2 -History of Pirana Satpanth -Gujarati Book
Series 40 - Satya prakash  v2 -History of Pirana Satpanth -Gujarati Book Series 40 - Satya prakash  v2 -History of Pirana Satpanth -Gujarati Book
Series 40 - Satya prakash v2 -History of Pirana Satpanth -Gujarati Book
 
Asthma
AsthmaAsthma
Asthma
 

Similar a Capa de persistencia con ecto

Intro a cakephp
Intro a cakephpIntro a cakephp
Intro a cakephpbetabeers
 
Efc programación .net-luis fernando aguas - 22012022 1700
Efc programación .net-luis fernando aguas - 22012022 1700Efc programación .net-luis fernando aguas - 22012022 1700
Efc programación .net-luis fernando aguas - 22012022 1700Luis Fernando Aguas Bucheli
 
EFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptx
EFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptxEFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptx
EFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptxLuis Fernando Aguas Bucheli
 
Cross development - React para desarrolladores de asp.net
Cross development - React para desarrolladores de asp.netCross development - React para desarrolladores de asp.net
Cross development - React para desarrolladores de asp.netAlberto Diaz Martin
 
CrossDvlpu - REACT para desarrolladores de ASP.NET
CrossDvlpu - REACT para desarrolladores de ASP.NETCrossDvlpu - REACT para desarrolladores de ASP.NET
CrossDvlpu - REACT para desarrolladores de ASP.NETAlberto Diaz Martin
 
Un framework para la generación automática de ejercicios mediante técnicas de...
Un framework para la generación automática de ejercicios mediante técnicas de...Un framework para la generación automática de ejercicios mediante técnicas de...
Un framework para la generación automática de ejercicios mediante técnicas de...Pablo Gómez Abajo
 
Angular 2 Campus Madrid Septiembre 2016
Angular 2 Campus Madrid Septiembre 2016Angular 2 Campus Madrid Septiembre 2016
Angular 2 Campus Madrid Septiembre 2016Micael Gallego
 
cream code with objective-c
cream code with objective-ccream code with objective-c
cream code with objective-cidealistaimasd
 
Unit Testing - GTUG
Unit Testing - GTUGUnit Testing - GTUG
Unit Testing - GTUGJordi Gerona
 
01 Ext Js Introduccion
01 Ext Js   Introduccion01 Ext Js   Introduccion
01 Ext Js IntroduccionMayer Horna
 
Hands-on Spring 3: The next generation
Hands-on Spring 3: The next generationHands-on Spring 3: The next generation
Hands-on Spring 3: The next generationSergi Almar i Graupera
 
Creación de aplicaciones web con Node.js y Express
Creación de aplicaciones web con Node.js y ExpressCreación de aplicaciones web con Node.js y Express
Creación de aplicaciones web con Node.js y Expressbetabeers
 
IntroduccióN A Sql Server 2005
IntroduccióN A Sql Server 2005IntroduccióN A Sql Server 2005
IntroduccióN A Sql Server 2005oswchavez
 

Similar a Capa de persistencia con ecto (20)

Introducción a Angular
Introducción a AngularIntroducción a Angular
Introducción a Angular
 
Concurrencia en Java
Concurrencia en Java Concurrencia en Java
Concurrencia en Java
 
Intro a cakephp
Intro a cakephpIntro a cakephp
Intro a cakephp
 
Intro a cakephp
Intro a cakephpIntro a cakephp
Intro a cakephp
 
Efc programación .net-luis fernando aguas - 22012022 1700
Efc programación .net-luis fernando aguas - 22012022 1700Efc programación .net-luis fernando aguas - 22012022 1700
Efc programación .net-luis fernando aguas - 22012022 1700
 
EFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptx
EFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptxEFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptx
EFC-Programación .net-Luis Fernando Aguas - 15012022 1500.pptx
 
Cross development - React para desarrolladores de asp.net
Cross development - React para desarrolladores de asp.netCross development - React para desarrolladores de asp.net
Cross development - React para desarrolladores de asp.net
 
CrossDvlpu - REACT para desarrolladores de ASP.NET
CrossDvlpu - REACT para desarrolladores de ASP.NETCrossDvlpu - REACT para desarrolladores de ASP.NET
CrossDvlpu - REACT para desarrolladores de ASP.NET
 
Un framework para la generación automática de ejercicios mediante técnicas de...
Un framework para la generación automática de ejercicios mediante técnicas de...Un framework para la generación automática de ejercicios mediante técnicas de...
Un framework para la generación automática de ejercicios mediante técnicas de...
 
Software de Búsqueda
Software de BúsquedaSoftware de Búsqueda
Software de Búsqueda
 
Angular 2 Campus Madrid Septiembre 2016
Angular 2 Campus Madrid Septiembre 2016Angular 2 Campus Madrid Septiembre 2016
Angular 2 Campus Madrid Septiembre 2016
 
cream code with objective-c
cream code with objective-ccream code with objective-c
cream code with objective-c
 
Generador codigo
Generador codigoGenerador codigo
Generador codigo
 
Unit Testing - GTUG
Unit Testing - GTUGUnit Testing - GTUG
Unit Testing - GTUG
 
01 Ext Js Introduccion
01 Ext Js   Introduccion01 Ext Js   Introduccion
01 Ext Js Introduccion
 
Javascript
JavascriptJavascript
Javascript
 
Hands-on Spring 3: The next generation
Hands-on Spring 3: The next generationHands-on Spring 3: The next generation
Hands-on Spring 3: The next generation
 
Creación de aplicaciones web con Node.js y Express
Creación de aplicaciones web con Node.js y ExpressCreación de aplicaciones web con Node.js y Express
Creación de aplicaciones web con Node.js y Express
 
 
IntroduccióN A Sql Server 2005
IntroduccióN A Sql Server 2005IntroduccióN A Sql Server 2005
IntroduccióN A Sql Server 2005
 

Más de Rafael Antonio Gutiérrez Turullols (7)

Java Collection Framework: lo que todo Java Dev debe conocer
Java Collection Framework: lo que todo Java Dev debe conocerJava Collection Framework: lo que todo Java Dev debe conocer
Java Collection Framework: lo que todo Java Dev debe conocer
 
De Threads a CompletableFutures
De Threads a CompletableFuturesDe Threads a CompletableFutures
De Threads a CompletableFutures
 
Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017
Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017
Building a Slack Bot Workshop @ Nearsoft OctoberTalks 2017
 
Una gota de elixir 2017
Una gota de elixir   2017Una gota de elixir   2017
Una gota de elixir 2017
 
Elixir concurrency 101
Elixir concurrency 101Elixir concurrency 101
Elixir concurrency 101
 
Test doubles and EasyMock
Test doubles and EasyMockTest doubles and EasyMock
Test doubles and EasyMock
 
Dando saltos con Spring Roo
Dando saltos con Spring RooDando saltos con Spring Roo
Dando saltos con Spring Roo
 

Capa de persistencia con ecto

  • 1. Capa de Persistencia con Ecto Rafael Gutiérrez, @abaddon_gtz Julio 23, 2016 @ElixirLangMx
  • 2. Ecto ● Framework de persistencia para Elixir (hecho en Elixir) ● Diseñado para bases de datos relacionales ● Ideas de LINQ de .NET y ActiveRecord de Rails ● Wrapper de la base de datos ● Lenguaje de consulta integrado (language integrated query - LIQ) !! ○ DSL
  • 3. LINQ & Ecto & SQL # Elixir from c in Customer, where: c.city == “Mexico”, select: c.company_name // C# from c in db.Customers where c.City == “Mexico” select c.CompanyName -- SQL SELECTcompany_name FROM customer WHERE city = ‘Mexico’
  • 4. Beneficios de un LIQ ● Metadatos ● Validación de sintaxis en tiempo de compilación ● Tipos ● Seguridad ● Composición
  • 5. Componentes de Ecto ● Ecto.Repo ● Ecto.Schema ● Ecto.Changeset ● Ecto.Query
  • 6. Caso de Estudio Administrar las propuestas de Workshops
  • 7. Ecto.Repo ● Wrapper de la base de datos ● Via el Repo, creamos, consultamos, borramos y actualizamos los datos ● Usa un Adapter para comunicarse a la BD
  • 8. Crear el proyecto con mix ● > mix new wsp_app --sup ● --sup para generar una aplicación OTP con árbol de supervisión ● Ecto.Repo corre bajo un árbol de supervisión
  • 9. Dependencias # mix.exs defp deps do [{:postgrex, ">= 0.0.0"}, {:ecto, "~> 2.0.0"}] end # mix.exs def application do [applications: [:logger, :ecto, :postgrex], mod: {WspApp, []}] end
  • 10. Repositorio y árbol de supervisión # Nuevo archivo /lib/wsp_app/repo.ex defmodule WspApp.Repo do use Ecto.Repo, otp_app: :wsp_app End # Agregar el repo al árbol de supervisión /lib/wsp_app.ex def start(_type, _args) do import Supervisor.Spec, warn: false children = [supervisor(WspApp.Repo, [])] opts = [strategy: :one_for_one, name: WspApp.Supervisor] Supervisor.start_link(children, opts) end
  • 11. Adapter # Configurar el Adapter /config/config.exs config :wsp_app, WspApp.Repo, adapter: Ecto.Adapters.Postgres, database: "ws_proposal_app_dev", username: "postgres", password: "", hostname: "localhost" # pool_size: 20 # desde Ecto 2 config :wsp_app, ecto_repos: [WspApp.Repo]
  • 12. Ecto.Schema ● Mapea la fuente de datos a un struct de Elixir ● Usado para mapear la tabla a datos de Elixir
  • 13. Migration - workshop_proposals # > mix ecto.gen.migration create_workshop_proposals_table # /priv/repo/migrations/ defmodule WspApp.Repo.Migrations.CreateWorkshopProposalsTable do use Ecto.Migration def change do create table(:workshop_proposals) do add :title, :text add :description, :text add :instructor_email, :text add :tentative_date, :date timestamps end end end
  • 14. Migration - votes # > mix ecto.gen.migration create_votes_table # /priv/repo/migrations/ defmodule WspApp.Repo.Migrations.CreateVotesTable do use Ecto.Migration def change do create table(:votes) do add :email, :text add :workshop_proposal_id, references(:workshop_proposals, [on_delete: :delete_all, on_update: :update_all]) timestamps end end end
  • 15. Migration - unique index para votes # > mix ecto.gen.migration create_unique_vote_constraint # /priv/repo/migrations/ defmodule WspApp.Repo.Migrations.CreateUniqueVoteConstraint do use Ecto.Migration def change do create unique_index(:votes, [:email, :workshop_proposal_id]) end end
  • 16. Modelo - WorkshopProposal # /lib/wsp_app/workshop_proposal.ex defmodule WspApp.WorkshopProposal do use Ecto.Schema schema "workshop_proposals" do field :title, :string field :description, :string field :instructor_email, :string field :tentative_date, Ecto.Date has_many :votes, WspApp.Vote timestamps end end
  • 17. Modelo - Vote # /lib/wsp_app/vote.ex defmodule WspApp.Vote do use Ecto.Schema import Ecto.Changeset schema "votes" do field :email, :string belongs_to :workshop_proposal, WspApp.WorkshopProposal, foreign_key: :workshop_proposal_id timestamps end end
  • 18. Ecto.Changeset ● Filtran y hacen ‘cast’ de parametros externos. ● Provee mecanismos para dar seguimiento (tracking) y validación de cambios.
  • 19. WorkshopProposal Changeset v1 # /lib/wsp_app/workshop_proposal.ex defmodule WspApp.WorkshopProposal do use Ecto.Schema import Ecto.Changeset # ... schema def changeset(workshop_proposal, params %{}) do workshop_proposal |> cast(params, [:title, :description, :instructor_email, :tentative_date]) |> validate_required([:title, :instructor_email, :tentative_date]) end end
  • 20. WorkshopProposal Changeset v2 def changeset(workshop_proposal, params %{}) do workshop_proposal |> cast(params, [:title, :description, :instructor_email, :tentative_date]) |> validate_required([:title, :instructor_email, :tentative_date]) |> validate_format(:instructor_email, ~r/@/) |> validate_change(:tentative_date, fn(:tentative_date, tentative_date) -> case Ecto.Date.compare(tentative_date, Ecto.Date.from_erl(:erlang.date())) do :lt -> [tentative_date: "cannot be less than today"] :gt -> [] :eq -> [] end end) end
  • 21. Vote Changeset # /lib/wsp_app/vote.ex defmodule WspApp.Vote do use Ecto.Schema import Ecto.Changeset # ... def changeset(vote, params %{}) do vote |> cast(params, [:email, :workshop_proposal_id]) |> validate_required([:email, :workshop_proposal_id]) |> validate_format(:email, ~r/@/) end end
  • 22. Ecto.Changeset Struct ● Algunos campos son: ○ valid? - si el changeset es válido ○ data - la fuente de datos ○ changes - los cambios aplicados ○ errors - los errores después de las validaciones
  • 23. Ecto.Query ● Consultas SQL escritas en Elixir ● Son seguras porque evitan problemas como SQL Injection ● Son “armables”
  • 24. Consultas sencillas import Ecto.Query # SELECT * FROM workshop_proposal WspApp.Repo.all(from w in WspApp.WorkshopProposal) # SELECT id, title, instructor_email FROM workshop_proposal WspApp.Repo.all(from w in WspApp.WorkshopProposal, select: [w.id, w.title, w.instructor_email]) # SELECT * from workshop_proposal WHERE instructor_email = 'rgutierrez@nearsoft.com' WspApp.Repo.all(from w in WspApp.WorkshopProposal, where: w.instructor_email == "rgutierrez@nearsof.com")
  • 25. Interpolacion y ‘Casting’ import Ecto.Query date = Ecto.Date.cast!("2016-09-10") WspApp.Repo.all(from w in WspApp.WorkshopProposal, where: w.tentative_date > ^date) email = "rgutierrez@nearsoft.com" WspApp.Repo.all(from w in WspApp.WorkshopProposal, where: w.instructor_email == ^email) # Error: ** (Ecto.QueryError) iex:7: value `"0"` cannot be dumped to type :id. WspApp.Repo.all(from w in WspApp.WorkshopProposal, where: w.id > "0")
  • 26. Composicion query = from w in WspApp.WorkshopProposal, where: w.tentative_date > ^Ecto.Date.cast!("2016-09-10") WspApp.Repo.all(query) WspApp.Repo.all(from w in query, select: w.title) WspApp.Repo.all(from w in query, select: {w.title, w.instructor_email}, where: w.instructor_email not in ["rgutierrez@nearsoft.com"])
  • 27. Paginación WspApp.Repo.all(from w in WspApp.WorkshopProposal, limit: 10, offset: 0) WspApp.Repo.all(from w in WspApp.WorkshopProposal, limit: 10, offset: 10)
  • 28. Operadores de Agregación y Joins WspApp.Repo.all(from w in WspApp.WorkshopProposal, join: v in WspApp.Vote, on: v.workshop_proposal_id == w.id, where: v.workshop_proposal_id == w.id, select: {w.title, count(v.id)}, group_by: w.title) # gracias a la asociación WspApp.Repo.all(from w in WspApp.WorkshopProposal, join: v in WspApp.Vote, where: v.workshop_proposal_id == w.id, select: {w.title, count(v.id)}, group_by: w.title) ● count, avg, sum, min, max, group_by, having, order_by
  • 29. Fragments ● Cuando se requiere usar funciones/operaciones específicas del manejador de base de datos. from p in Post, where: is_nil(p.published_at) and fragment("downcase(?)", p.title) == ^title startTime = Ecto.DateTime.cast!({{2016, 11, 11}, {18, 00, 00}}) endTime = Ecto.DateTime.cast!({{2016, 11, 11}, {20, 00, 00}}) from c in Workshop, where: fragment("(?, ?) OVERLAPS (?, ?)", c.start, c.end, type(^startTime, Ecto.DateTime), type(^endTime, Ecto.DateTime))