Update ecto
This commit is contained in:
parent
c277cd3227
commit
38bbb94f7c
174
phoenix-ecto.md
174
phoenix-ecto.md
|
@ -1,177 +1,5 @@
|
||||||
---
|
---
|
||||||
title: "Phoenix: Ecto models"
|
title: "Phoenix: Ecto models"
|
||||||
category: Elixir
|
category: Elixir
|
||||||
|
redirect_to: /phoenix-ecto@1.3
|
||||||
---
|
---
|
||||||
|
|
||||||
This is for Phoenix 1.2 and below. [Phoenix 1.3 has a new API.](phoenix-ecto@1.3.html).
|
|
||||||
|
|
||||||
## Generating
|
|
||||||
|
|
||||||
```
|
|
||||||
$ mix phoenix.gen.html Profile profiles email:string age:integer
|
|
||||||
$ mix phoenix.gen.html User users email:string hashed_password:string
|
|
||||||
```
|
|
||||||
|
|
||||||
## Schema
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
defmodule User do
|
|
||||||
use Ecto.Schema
|
|
||||||
|
|
||||||
schema "users" do
|
|
||||||
field :name
|
|
||||||
field :age, :integer
|
|
||||||
# :id :binary :integer :float :boolean :string :binary
|
|
||||||
# {:array, inner_type} :decimal :map
|
|
||||||
|
|
||||||
field :password, virtual: true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
## Changesets
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
def changeset(user, params \\ :empty) do
|
|
||||||
%User{}
|
|
||||||
|> Ecto.Changeset.change # basic casting to changeset
|
|
||||||
|
|
||||||
user
|
|
||||||
|> cast(params, ~w(name email), ~w(age)) # params to Changeset
|
|
||||||
|
|
||||||
|> validate_format(:email, ~r/@/)
|
|
||||||
|
|
||||||
|> validate_inclusion(:age, 18..100)
|
|
||||||
|> validate_exclusion(:role, ~w(admin superadmin))
|
|
||||||
|> validate_subset(:pets, ~w(cat dog parrot whale))
|
|
||||||
|
|
||||||
|> validate_length(:body, min: 1)
|
|
||||||
|> validate_length(:body, min: 1, max: 160)
|
|
||||||
|> validate_length(:partners, is: 2)
|
|
||||||
|
|
||||||
|> validate_number(:pi, greater_than: 3)
|
|
||||||
|> validate_number(:pi, less_than: 4)
|
|
||||||
|> validate_number(:pi, equal_to: 42)
|
|
||||||
|
|
||||||
|> validate_change(:title, fn _, _ -> [])
|
|
||||||
|> validate_confirmation(:password, message: "does not match")
|
|
||||||
|
|
||||||
|> unique_constraint(:email)
|
|
||||||
|> foreign_key_constraint(:post_id)
|
|
||||||
|> assoc_constraint(:post) # ensure post_id exists
|
|
||||||
|> no_assoc_constraint(:post) # negative (useful for deletions)
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
changeset.valid?
|
|
||||||
changeset.errors #=> [title: "empty"]
|
|
||||||
|
|
||||||
changeset.changes #=> %{}
|
|
||||||
changeset.params[:title]
|
|
||||||
|
|
||||||
changeset.required #=> [:title]
|
|
||||||
changeset.optional #=> [:body]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Updating
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
changeset #(or model)
|
|
||||||
|> change(title: "New title")
|
|
||||||
|> change(%{ title: "New title" })
|
|
||||||
|> put_change(:title, "New title")
|
|
||||||
|> force_change(:title, "New title")
|
|
||||||
|> update_change(:title, &(&1 <> "..."))
|
|
||||||
|
|
||||||
|> delete_change(:title)
|
|
||||||
|> merge(other_changeset)
|
|
||||||
|
|
||||||
|> add_error(:title, "empty")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Getting
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
get_change(changeset, :title) #=> "hi" (if changed)
|
|
||||||
get_field(changeset, :title) #=> "hi" (even if unchanged)
|
|
||||||
|
|
||||||
fetch_change(changeset, :title) #=> {:ok, "hi"} | :error
|
|
||||||
fetch_field(changeset, :title) #=> {:changes | :model, "value"} | :error
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ecto
|
|
||||||
|
|
||||||
### Get one
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
Repo.get(User, id)
|
|
||||||
Repo.get_by(User, email: "john@hello.com") #=> %User{} | nil
|
|
||||||
|
|
||||||
# also get! get_by!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Create/update
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
changeset |> Repo.update
|
|
||||||
changeset |> Repo.insert
|
|
||||||
changeset |> Repo.insert_or_update
|
|
||||||
```
|
|
||||||
|
|
||||||
```
|
|
||||||
User
|
|
||||||
|> Ecto.Changeset.change(%{name: "hi"})
|
|
||||||
|> Repo.insert
|
|
||||||
```
|
|
||||||
|
|
||||||
## Many
|
|
||||||
|
|
||||||
### Queries
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
from p in Post,
|
|
||||||
where: p.title == "Hello",
|
|
||||||
where: [state: "Sweden"],
|
|
||||||
|
|
||||||
limit: 1,
|
|
||||||
offset: 10,
|
|
||||||
|
|
||||||
order_by: c.name,
|
|
||||||
order_by: [c.name, c.title],
|
|
||||||
order_by: [asc: c.name, desc: c.title],
|
|
||||||
|
|
||||||
preload: [:comments],
|
|
||||||
preload: [comments: {c, likes: l}],
|
|
||||||
|
|
||||||
join: c in assoc(c, :comments),
|
|
||||||
join: p in Post, on: c.post_id == p.id,
|
|
||||||
group_by: p,
|
|
||||||
|
|
||||||
select: p,
|
|
||||||
select: {p.title, p.description},
|
|
||||||
select: [p.title, p.description],
|
|
||||||
```
|
|
||||||
|
|
||||||
### Get many
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
Repo.all(User)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Update many
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
Repo.update_all(Post, set: [title: "Title"])
|
|
||||||
Repo.update_all(Post, inc: [views: 1])
|
|
||||||
```
|
|
||||||
|
|
||||||
### Chaining `_all` with queries
|
|
||||||
|
|
||||||
```elixir
|
|
||||||
from(p in Post, where: p.id < 10)
|
|
||||||
|> Repo.update_all(...)
|
|
||||||
|
|
||||||
from(p in Post, where: p.id < 10)
|
|
||||||
|> Repo.all()
|
|
||||||
```
|
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
---
|
||||||
|
title: "Phoenix: Ecto models"
|
||||||
|
category: Elixir
|
||||||
|
---
|
||||||
|
|
||||||
|
This is for Phoenix 1.2 and below. [Phoenix 1.3 has a new API.](phoenix-ecto@1.3.html).
|
||||||
|
|
||||||
|
## Generating
|
||||||
|
|
||||||
|
```
|
||||||
|
$ mix phoenix.gen.html Profile profiles email:string age:integer
|
||||||
|
$ mix phoenix.gen.html User users email:string hashed_password:string
|
||||||
|
```
|
||||||
|
|
||||||
|
## Schema
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
defmodule User do
|
||||||
|
use Ecto.Schema
|
||||||
|
|
||||||
|
schema "users" do
|
||||||
|
field :name
|
||||||
|
field :age, :integer
|
||||||
|
# :id :binary :integer :float :boolean :string :binary
|
||||||
|
# {:array, inner_type} :decimal :map
|
||||||
|
|
||||||
|
field :password, virtual: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
## Changesets
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
def changeset(user, params \\ :empty) do
|
||||||
|
%User{}
|
||||||
|
|> Ecto.Changeset.change # basic casting to changeset
|
||||||
|
|
||||||
|
user
|
||||||
|
|> cast(params, ~w(name email), ~w(age)) # params to Changeset
|
||||||
|
|
||||||
|
|> validate_format(:email, ~r/@/)
|
||||||
|
|
||||||
|
|> validate_inclusion(:age, 18..100)
|
||||||
|
|> validate_exclusion(:role, ~w(admin superadmin))
|
||||||
|
|> validate_subset(:pets, ~w(cat dog parrot whale))
|
||||||
|
|
||||||
|
|> validate_length(:body, min: 1)
|
||||||
|
|> validate_length(:body, min: 1, max: 160)
|
||||||
|
|> validate_length(:partners, is: 2)
|
||||||
|
|
||||||
|
|> validate_number(:pi, greater_than: 3)
|
||||||
|
|> validate_number(:pi, less_than: 4)
|
||||||
|
|> validate_number(:pi, equal_to: 42)
|
||||||
|
|
||||||
|
|> validate_change(:title, fn _, _ -> [])
|
||||||
|
|> validate_confirmation(:password, message: "does not match")
|
||||||
|
|
||||||
|
|> unique_constraint(:email)
|
||||||
|
|> foreign_key_constraint(:post_id)
|
||||||
|
|> assoc_constraint(:post) # ensure post_id exists
|
||||||
|
|> no_assoc_constraint(:post) # negative (useful for deletions)
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
changeset.valid?
|
||||||
|
changeset.errors #=> [title: "empty"]
|
||||||
|
|
||||||
|
changeset.changes #=> %{}
|
||||||
|
changeset.params[:title]
|
||||||
|
|
||||||
|
changeset.required #=> [:title]
|
||||||
|
changeset.optional #=> [:body]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
changeset #(or model)
|
||||||
|
|> change(title: "New title")
|
||||||
|
|> change(%{ title: "New title" })
|
||||||
|
|> put_change(:title, "New title")
|
||||||
|
|> force_change(:title, "New title")
|
||||||
|
|> update_change(:title, &(&1 <> "..."))
|
||||||
|
|
||||||
|
|> delete_change(:title)
|
||||||
|
|> merge(other_changeset)
|
||||||
|
|
||||||
|
|> add_error(:title, "empty")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Getting
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
get_change(changeset, :title) #=> "hi" (if changed)
|
||||||
|
get_field(changeset, :title) #=> "hi" (even if unchanged)
|
||||||
|
|
||||||
|
fetch_change(changeset, :title) #=> {:ok, "hi"} | :error
|
||||||
|
fetch_field(changeset, :title) #=> {:changes | :model, "value"} | :error
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ecto
|
||||||
|
|
||||||
|
### Get one
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
Repo.get(User, id)
|
||||||
|
Repo.get_by(User, email: "john@hello.com") #=> %User{} | nil
|
||||||
|
|
||||||
|
# also get! get_by!
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create/update
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
changeset |> Repo.update
|
||||||
|
changeset |> Repo.insert
|
||||||
|
changeset |> Repo.insert_or_update
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
User
|
||||||
|
|> Ecto.Changeset.change(%{name: "hi"})
|
||||||
|
|> Repo.insert
|
||||||
|
```
|
||||||
|
|
||||||
|
## Many
|
||||||
|
|
||||||
|
### Queries
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
from p in Post,
|
||||||
|
where: p.title == "Hello",
|
||||||
|
where: [state: "Sweden"],
|
||||||
|
|
||||||
|
limit: 1,
|
||||||
|
offset: 10,
|
||||||
|
|
||||||
|
order_by: c.name,
|
||||||
|
order_by: [c.name, c.title],
|
||||||
|
order_by: [asc: c.name, desc: c.title],
|
||||||
|
|
||||||
|
preload: [:comments],
|
||||||
|
preload: [comments: {c, likes: l}],
|
||||||
|
|
||||||
|
join: c in assoc(c, :comments),
|
||||||
|
join: p in Post, on: c.post_id == p.id,
|
||||||
|
group_by: p,
|
||||||
|
|
||||||
|
select: p,
|
||||||
|
select: {p.title, p.description},
|
||||||
|
select: [p.title, p.description],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get many
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
Repo.all(User)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update many
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
Repo.update_all(Post, set: [title: "Title"])
|
||||||
|
Repo.update_all(Post, inc: [views: 1])
|
||||||
|
```
|
||||||
|
|
||||||
|
### Chaining `_all` with queries
|
||||||
|
|
||||||
|
```elixir
|
||||||
|
from(p in Post, where: p.id < 10)
|
||||||
|
|> Repo.update_all(...)
|
||||||
|
|
||||||
|
from(p in Post, where: p.id < 10)
|
||||||
|
|> Repo.all()
|
||||||
|
```
|
|
@ -1,16 +1,19 @@
|
||||||
---
|
---
|
||||||
title: "Phoenix: Ecto models"
|
title: "Phoenix: Ecto models"
|
||||||
category: Elixir
|
category: Elixir
|
||||||
|
layout: 2017/sheet
|
||||||
|
tags: [WIP]
|
||||||
|
updated: 201708.29
|
||||||
---
|
---
|
||||||
|
|
||||||
## Generating
|
### Generating
|
||||||
|
|
||||||
```
|
```
|
||||||
$ mix phx.gen.html Accounts Profile profiles email:string age:integer
|
$ mix phx.gen.html Accounts Profile profiles email:string age:integer
|
||||||
$ mix phx.gen.html Accounts User users email:string hashed_password:string
|
$ mix phx.gen.html Accounts User users email:string hashed_password:string
|
||||||
```
|
```
|
||||||
|
|
||||||
## Schema
|
### Schema
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
defmodule Myapp.Accounts.User do
|
defmodule Myapp.Accounts.User do
|
||||||
|
@ -31,6 +34,8 @@ end
|
||||||
|
|
||||||
## Changesets
|
## Changesets
|
||||||
|
|
||||||
|
### Changesets
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
def changeset(user, params \\ :empty) do
|
def changeset(user, params \\ :empty) do
|
||||||
%User{}
|
%User{}
|
||||||
|
@ -63,6 +68,8 @@ def changeset(user, params \\ :empty) do
|
||||||
end
|
end
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Changeset fields
|
||||||
|
|
||||||
```elixir
|
```elixir
|
||||||
changeset.valid?
|
changeset.valid?
|
||||||
changeset.errors #=> [title: "empty"]
|
changeset.errors #=> [title: "empty"]
|
||||||
|
@ -100,7 +107,7 @@ fetch_change(changeset, :title) #=> {:ok, "hi"} | :error
|
||||||
fetch_field(changeset, :title) #=> {:changes | :model, "value"} | :error
|
fetch_field(changeset, :title) #=> {:changes | :model, "value"} | :error
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ecto
|
## Repo
|
||||||
|
|
||||||
### Get one
|
### Get one
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue