mirror of
https://github.com/onkelbeh/cheatsheets.git
synced 2025-06-15 14:47:53 +02:00
Rename phoenix-ecto@1.3 to phoenix-ecto
This commit is contained in:
parent
0d4e4095ed
commit
472f6b3ae6
209
phoenix-ecto.md
209
phoenix-ecto.md
@ -1,5 +1,210 @@
|
||||
---
|
||||
title: "Phoenix: Ecto models"
|
||||
title: "Phoenix: Ecto"
|
||||
category: Elixir
|
||||
redirect_to: /phoenix-ecto@1.3
|
||||
layout: 2017/sheet
|
||||
tags: [WIP]
|
||||
updated: 201708.29
|
||||
---
|
||||
|
||||
## Schemas
|
||||
{: .-three-column}
|
||||
|
||||
### Generating
|
||||
|
||||
```bash
|
||||
$ mix phx.gen.html \
|
||||
Accounts \ # domain
|
||||
Profile \ # schema
|
||||
profiles \ # table name
|
||||
email:string \
|
||||
age:integer
|
||||
```
|
||||
|
||||
### Schema
|
||||
|
||||
```elixir
|
||||
defmodule Myapp.Accounts.User do
|
||||
use Ecto.Schema
|
||||
|
||||
schema "users" do
|
||||
field :name
|
||||
field :age, :integer
|
||||
field :password, virtual: true
|
||||
|
||||
timestamps()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Field types
|
||||
|
||||
| Field |
|
||||
| --- |
|
||||
| `:id` |
|
||||
| `:binary` |
|
||||
| `:boolean` |
|
||||
| `:string` |
|
||||
| --- |
|
||||
| `:integer` |
|
||||
| `:float` |
|
||||
| `:decimal` |
|
||||
| --- |
|
||||
| `{:array, inner_type}` |
|
||||
| `:map` |
|
||||
{: .-left-align}
|
||||
|
||||
## Changesets
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
### Changeset fields
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## Repo
|
||||
|
||||
### 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()
|
||||
```
|
||||
|
||||
## References
|
||||
{: .-one-column}
|
||||
|
||||
- Based on Ecto 1.3.
|
||||
|
@ -1,205 +1,5 @@
|
||||
---
|
||||
title: "Phoenix: Ecto"
|
||||
title: "Phoenix: Ecto models"
|
||||
category: Elixir
|
||||
layout: 2017/sheet
|
||||
tags: [WIP]
|
||||
updated: 201708.29
|
||||
redirect_to: /phoenix-ecto
|
||||
---
|
||||
|
||||
## Schemas
|
||||
{: .-three-column}
|
||||
|
||||
### Generating
|
||||
|
||||
```bash
|
||||
$ mix phx.gen.html \
|
||||
Accounts \ # domain
|
||||
Profile \ # schema
|
||||
profiles \ # table name
|
||||
email:string \
|
||||
age:integer
|
||||
```
|
||||
|
||||
### Schema
|
||||
|
||||
```elixir
|
||||
defmodule Myapp.Accounts.User do
|
||||
use Ecto.Schema
|
||||
|
||||
schema "users" do
|
||||
field :name
|
||||
field :age, :integer
|
||||
field :password, virtual: true
|
||||
|
||||
timestamps()
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
### Field types
|
||||
|
||||
| Field |
|
||||
| --- |
|
||||
| `:id` |
|
||||
| `:binary` |
|
||||
| `:boolean` |
|
||||
| `:string` |
|
||||
| --- |
|
||||
| `:integer` |
|
||||
| `:float` |
|
||||
| `:decimal` |
|
||||
| --- |
|
||||
| `{:array, inner_type}` |
|
||||
| `:map` |
|
||||
{: .-left-align}
|
||||
|
||||
## Changesets
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
### Changeset fields
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
## Repo
|
||||
|
||||
### 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()
|
||||
```
|
||||
|
Loading…
x
Reference in New Issue
Block a user