Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Ecto: a database wrapper and language integrated query for Elixir

Ecto: a database wrapper and language integrated query for Elixir

Arjan van der Gaag

October 28, 2015
Tweet

More Decks by Arjan van der Gaag

Other Decks in Programming

Transcript

  1. ecto
    a database wrapper and language
    integrated query for Elixir

    View full-size slide

  2. defmodule Weather do
    use Ecto.Model
    schema "weather" do
    field :city # Defaults to type :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp, :float, default: 0.0
    end
    end
    query = from w in Weather,
    where: w.prcp > 0 or is_nil(w.prcp),
    select: w
    Repo.all(query)

    View full-size slide

  3. simplicity over
    convenience

    View full-size slide

  4. “If you want Ecto to get something, you
    have to explicitly ask for it. This
    feature will probably seem a little
    tedious to you…”

    View full-size slide

  5. “…but it is the only way to guarantee
    your application has predictable
    performance when the amount of
    data grows.”

    View full-size slide

  6. defmodule Weather do
    use Ecto.Model
    schema "weather" do
    field :city # Defaults to type :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp, :float, default: 0.0
    end
    end
    query = from w in Weather,
    where: w.prcp > 0 or is_nil(w.prcp),
    select: w
    Repo.all(query)

    View full-size slide

  7. defmodule Weather do
    use Ecto.Model
    schema "weather" do
    field :city # Defaults to type :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp, :float, default: 0.0
    end
    end
    query = from w in Weather,
    where: w.prcp > 0 or is_nil(w.prcp),
    select: w
    Repo.all(query)

    View full-size slide

  8. defmodule Weather do
    use Ecto.Model
    schema "weather" do
    field :city # Defaults to type :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp, :float, default: 0.0
    end
    end
    query = from w in Weather,
    where: w.prcp > 0 or is_nil(w.prcp),
    select: w
    Repo.all(query)

    View full-size slide

  9. defmodule Weather do
    use Ecto.Model
    schema "weather" do
    field :city # Defaults to type :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp, :float, default: 0.0
    end
    end
    query = from w in Weather,
    where: w.prcp > 0 or is_nil(w.prcp),
    select: w
    Repo.all(query)

    View full-size slide

  10. defmodule Weather do
    use Ecto.Model
    schema "weather" do
    field :city # Defaults to type :string
    field :temp_lo, :integer
    field :temp_hi, :integer
    field :prcp, :float, default: 0.0
    end
    end
    query = from w in Weather,
    where: w.prcp > 0 or is_nil(w.prcp),
    select: w
    Repo.all(query)

    View full-size slide

  11. ‣ data mapper
    ‣ query language
    ‣ associations
    ‣ filtering
    ‣ validations
    ‣ lifecycle callbacks
    ‣ changesets
    ‣ migrations
    ‣ custom types
    ‣ embedded structs

    View full-size slide

  12. compose queries

    View full-size slide

  13. # Create a query
    query = from w in Weather, where: w.prcp > 0
    # Extend the query
    query = from w in query, select: w.city

    View full-size slide

  14. Repo.get_by(Post, title: "My post")
    Repo.transaction(fn ->
    Repo.update!(%{alice | balance: alice.balance - 10})
    Repo.update!(%{bob | balance: bob.balance + 10})
    end)
    post = Repo.get!(Post, 42)
    post = %{post | title: "New title"}
    case Repo.update post do
    {:ok, model} -> # Updated with success
    {:error, changeset} -> # Something went wrong
    end

    View full-size slide

  15. Repo.get_by(Post, title: "My post")
    Repo.transaction(fn ->
    Repo.update!(%{alice | balance: alice.balance - 10})
    Repo.update!(%{bob | balance: bob.balance + 10})
    end)
    post = Repo.get!(Post, 42)
    post = %{post | title: "New title"}
    case Repo.update post do
    {:ok, model} -> # Updated with success
    {:error, changeset} -> # Something went wrong
    end

    View full-size slide

  16. Repo.get_by(Post, title: "My post")
    Repo.transaction(fn ->
    Repo.update!(%{alice | balance: alice.balance - 10})
    Repo.update!(%{bob | balance: bob.balance + 10})
    end)
    post = Repo.get!(Post, 42)
    post = %{post | title: "New title"}
    case Repo.update post do
    {:ok, model} -> # Updated with success
    {:error, changeset} -> # Something went wrong
    end

    View full-size slide

  17. defmodule User do
    use Ecto.Model
    import Ecto.Changeset
    schema "users" do
    field :name
    field :email
    field :age, :integer
    end
    def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> unique_constraint(:email)
    |> validate_inclusion(:age, 18..100)
    end
    end

    View full-size slide

  18. defmodule User do
    use Ecto.Model
    import Ecto.Changeset
    schema "users" do
    field :name
    field :email
    field :age, :integer
    end
    def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> unique_constraint(:email)
    |> validate_inclusion(:age, 18..100)
    end
    end

    View full-size slide

  19. defmodule User do
    use Ecto.Model
    import Ecto.Changeset
    schema "users" do
    field :name
    field :email
    field :age, :integer
    end
    def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> unique_constraint(:email)
    |> validate_inclusion(:age, 18..100)
    end
    end

    View full-size slide

  20. defmodule User do
    use Ecto.Model
    import Ecto.Changeset
    schema "users" do
    field :name
    field :email
    field :age, :integer
    end
    def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> unique_constraint(:email)
    |> validate_inclusion(:age, 18..100)
    end
    end

    View full-size slide

  21. defmodule User do
    use Ecto.Model
    import Ecto.Changeset
    schema "users" do
    field :name
    field :email
    field :age, :integer
    end
    def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> unique_constraint(:email)
    |> validate_inclusion(:age, 18..100)
    end
    end

    View full-size slide

  22. defmodule User do
    use Ecto.Model
    import Ecto.Changeset
    schema "users" do
    field :name
    field :email
    field :age, :integer
    end
    def changeset(user, params \\ :empty) do
    user
    |> cast(params, ~w(name email), ~w(age))
    |> validate_format(:email, ~r/@/)
    |> unique_constraint(:email)
    |> validate_inclusion(:age, 18..100)
    end
    end

    View full-size slide

  23. def registration_changeset(model, params) do
    model
    |> changeset(params)
    |> cast(params, ~w(password), [])
    |> validate_length(:password, min: 6, max: 100)
    |> put_pass_hash()
    end

    View full-size slide

  24. associations

    View full-size slide

  25. query = from p in Post, preload: [:comments]
    query = from p in Post,
    join: c in assoc(p, :comments),
    where: c.published_at > p.updated_at,
    preload: [comments: c]
    query |> Repo.all

    View full-size slide

  26. familiar
    different
    pragmatic
    fun

    View full-size slide