Ecto Getting Started (翻訳)

<https://hexdocs.pm/ecto/getting-started.html> (Ecto v2.0.5) の翻訳になります。

訳が間違っている、抜けているなどの箇所などを見つけたら指摘していただけると助かります。



---

# Getting Started

このガイドはElixirのデータベースラッパー及びクエリジェネレータ[Ecto](https://github.com/elixir-lang/ecto)へのイントロダクションです。Ectoは、Elixirデベロッパーがどんなデータベースを使っていようと同じような方法でクエリによる問い合わせができるように、標準化されたAPIと抽象化された方法を提供しています。

このガイドでは、PostgreSQLデータベースのレコードの作成・読み込み・更新・削除のような基本的なことについて学べます。もしこのガイド中のコードを見たければ、ここ([at ecto/examples/friends on GitHub](https://github.com/elixir-lang/ecto/tree/master/examples/friends))のコードを見てください。

**このガイドは事前にPostgreSQLがセットアップされているのを前提としています**

## Ectoのアプリケーションへの追加

手始めに、新しいElixirアプリケーションを作るため、以下のコマンドを使います。


```
mix new friends --sup
```

`--sup` オプションはこのアプリケーションが[a supervision tree](http://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html)を持っていること確認します。これは少し後で必要になります。

このアプリケーションにEctoを追加するのにいくつかのステップを踏む必要があります。最初のステップは`mix.exs` ファイルの `deps` を変更して、EctoとPostgrexというドライバを 追加することです。

```elixir
defp deps do
  [{:ecto, "~> 2.0"},
   {:postgrex, "~> 0.11"}]
end
```

Ectoは一般的なクエリAPIを提供しますが、EctoがPostgreSQLデータベースが解釈できる語で話すためにPostgrexドライバを必要とします。

以上の依存ファイルをインストールするためには、以下のコマンドを使います。

```
mix deps.get
```

同様に同じファイルで、`ecto` と `postgrex` を applicationsのリストに追加します。

```elixir
def application do
  [applications: [:logger, :ecto, :postgrex],
   mod: {Friends, []}]
end
```

PostgrexアプリケーションはEctoからクエリを受け取り、データベースに対してクエリを実行します。もしこのステップを踏まなければ、データベースに対する問い合わせはまったくできないでしょう。

二番目のステップに移りましょう。EctoとPostgrexを依存関係に組み込んだあとは、アプリケーションコードでデータベースを操作するためにいくつか設定が必要です。

この設定には以下のコマンドを使用します。

```
mix ecto.gen.repo -r Friends.Repo
```

このコマンドはデータベースと接続するための設定を生成します。`config/config.exs` は以下のような設定になります。

```elixir
config :friends, Friends.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "friends_repo",
  username: "user",
  password: "pass",
  hostname: "localhost"
```

**NOTE**: PostgreSQLデータベースは

- ユーザー名・パスワードを必要としないようにセットアップすることもできます。もし上の設定でうまくいかないなら、username/password のフィールドを取り除くか、どちらも"postgres"とセットすれば良いです。
- 非標準的なポートで動作させるようにセットアップすることもできます。`port: 15432` のようにポート番号を指定すれば良いです。

この設定により "friends" と名付けたデータベースへどのように接続するかを決めることができます。厳密に言えば "repo" を設定している。より詳しい情報は[Ecto.Repo can be found in its documentation](https://hexdocs.pm/ecto/Ecto.Repo.html)を参照すると良いです。

`Friends.Repo` モジュールは `mix ecto.gen.repo` コマンドで `lib/friends/repo.ex` に定義されています。

```elixir
defmodule Friends.Repo do
  use Ecto.Repo, otp_app: :friends
end
```

このモジュールはデータベースに問い合わせをするために使うものです。このモジュールは `Ecto.Repo` モジュールを使い、`otp_app` はEctoにどのElixirアプリケーションのデータベースの設定を探すかを伝えます。今回のガイドの場合、Ectoが設定ファイルを見つけることができるアプリケーションを `:friends` に指定しているのでEctoはセットアップ済みの設定を使うことができます。

この設定の最後のピースは、`Friends.Repo` をスーパーバイザーとして監視ツリーにセットアップすることです。`lib/friends.ex` の `start/2` 関数の中でセットアップはできます。

```elixir
def start(_type, _args) do
  import Supervisor.Spec, warn: false

  children = [
    supervisor(Friends.Repo, []),
  ]

  ...
```

この設定はEctoプロセスを開始させ、アプリケーションのクエリの受け取り及び実行することを可能にします。この設定なしではデータベースに問い合わせすることは全くできないでしょう!

最後にジェネレータが自動で加えてくれたりはしないので、自分自身を`config/config.exs` に以下のコードを追加します。

```elixir
config :friends, ecto_repos: [Friends.Repo]
```

このコードによって、`mix ecto.create` などのコマンドを動作させる repo についてアプリケーションに伝えることができます。

以上の設定で、データベースに問い合わせを行うことができるようにアプリケーションを設定することができました。続いてデータベース・テーブルを作成して問い合わせを行ってみましょう。

## データベースの設定

データベースへ問い合わせをするためには、データベースが存在してなければなりません。次のコマンドでデータベースを作成します。

```
mix ecto.create
```

もしデータベースがすでに作られているならば、次のメッセージが表示されます。

```
The database for Friends.Repo has been created.
```

**NOTE:** もしエラーになってしまったら、データベースへの認証が通るように `config/config.exs` の設定を変更する必要があります。

データベースだけでは問い合わせすることができないので、次にテーブルを作ります。テーブルを作るには _migration_ を行います。もしActive Recordやその類似品を知っているなら見たことがあるでしょう。マイグレーションはデータベースを構成する過程の一つのステップです。

マイグレーションは次のコマンドで作ることができます。

```
mix ecto.gen.migration create_people
```

このコマンドを実行すると `priv/repo/migrations` に新しいマイグレーション用のファイルを作成します。デフォルトでは空ファイルになります。

```elixir
defmodule Friends.Repo.Migrations.CreatePeople do
  use Ecto.Migration

  def change do

  end
end
```

いくつかのカラムを持った "people" テーブルを作るには、このファイルにいくつかコードを追加します。

```elixir
defmodule Friends.Repo.Migrations.CreatePeople do
  use Ecto.Migration

  def change do
    create table(:people) do
      add :first_name, :string
      add :last_name, :string
      add :age, :integer
    end
  end
end
```

この新しいコードによって `people` と名付けた新しいテーブルを作るようにEctoに伝えることができます。`first_name`、`last_name`、`age` がカラムとして追加されます。このフィールドの型は `string` と `integer` です。(Ectoがサポートする型は[Ecto.Schema](https://hexdocs.pm/ecto/Ecto.Schema.html)で見ることができます)

**NOTE**: Ectoデータベースのテーブルのネーミングルールは複数形です。

作成したマイグレーションを実行して `people` テーブルを作るには次のコマンドが必要です。

```
mix ecto.migrate
```

マイグレーションにミスを見つけたときは、`mix ecto.rollback` でそのマイグレーションの変更を打ち消すことができます。マイグレーションを修正したら再び `mix ecto.migrate` を実行します。`mix ecto.rollback` を一度実行してみると、作られたテーブルが削除されるのがわかるでしょう。

ここまででデータベースにテーブルを作成することができました。次のステップではスキーマを作成します。

## スキーマの作成

スキーマはデータベースのデータをElixirで表現したものです。スキーマは一般的にデータベースのテーブルと関連付けられていますが、データベースのビューとも同様付けることができます。

`lib/friends/person.ex` にスキーマを作ってみましょう。

```elixir
defmodule Friends.Person do
  use Ecto.Schema

  schema "people" do
    field :first_name, :string
    field :last_name, :string
    field :age, :integer
  end
end
```

このコードでデータベースのスキーマと対応するスキーマを定義できます。この場合、`Friends.Person` スキーマはデータベースの `people` テーブル、`first_name`・`last_name`・`age` フィールドと関連付けられます。

Ectoのネーミング変換は単数形のため、このスキーマを `Person` と呼びます。

このスキーマは `iex-S mix` で起動したIExセッションで試してみることができます。次のコードを実行してみましょう。

```elixir
person = %Friends.Person{}
```

このコードで新しく `Friends.Person` の構造を持ち各フィールドが `nil` の構造体が得られます。これらのフィールドは新しく構造体を作ることで値をセットすることができます。

```elixir
person = %Friends.Person{age: 28}
```

以下のような文法でも同様です。

```elixir
%{person | age: 28}
```

構造体の値は以下の文法で得ることができます。

```elixir
person.age # => 28
```

次にデータベースにどのようにデータを挿入するかを見ていきましょう。

## データの挿入

`people` テーブルに次のコードで新しいレコードを挿入できます。

```elixir
person = %Friends.Person{}
Friends.Repo.insert(person)
```

データベースにデータを挿入するには、`Friends.Repo` の `insert` を呼び出します。このモジュールはデータベースを使用するのに Ecto を使用しています。この関数は Ecto に `Friends.Repo` に対応するデータベースに 新しい `Friends.Person` レコードを挿入したいことを伝えます。ここでの `person` 構造体はデータベースに挿入したいデータを表しています。

挿入が成功した場合は次のようなタプルを返します。

```elixir
{:ok,
 %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: nil,
  first_name: nil, id: 1, last_name: nil}}
```

`:ok` アトムはデータ挿入が成功したことを確認するためにパターンマッチで使うことができます。挿入が失敗するシチュエーションはデータベース上で制約がある場合です。例えば、もしデータベースが email が一人のレコードのみに使われるようにするために、ユニーク制約を `email` フィールドにかけていたら挿入は失敗するでしょう。

データベースに挿入したレコードを参照したい場合、タプルにパターンマッチするようにすると良いです。

```elixir
{:ok, person} = Friends.Repo.insert person
```

## 変更の検証(バリデーション)

Ecto では、データベースに変更が伝わる前に、変更にバリデーションをかけたいと思うでしょう。例えば、データベースにレコードの情報が行く前に、一人の人が苗字と名前を持っていることを望むとしましょう。これを検証するために Ecto は [_changesets_](https://hexdocs.pm/ecto/Ecto.Changeset.html) を持っています。

`lib/friends/person.ex` の `Friends.Person` モジュールに changeset を追加しましょう。

```elixir
def changeset(person, params \\ %{}) do
  person
  |> Ecto.Changeset.cast(params, [:first_name, :last_name, :age])
  |> Ecto.Changeset.validate_required([:first_name, :last_name])
end
```

changeset は `person` とパラメーターセットを引数に取ります。このパラメーターセットは person に対して行いたい変更です。`changeset` 関数は渡されたパラメーターから `first_name` と `last_name` キーをキャストします。キャストはどのパラメーターが変更に含まれて良いかを決め、リストに含まれていないものは無視されます。

次の行では、`validate_required` を呼び出します。これは `first_name` と `last_name` が値を持っていることを期待します。この changeset を使って、`first_name` と `last_name` がない新しいレコードを作ろうとしてみましょう。

```elixir
person = %Friends.Person{}
changeset = Friends.Person.changeset(person, %{})
Friends.Repo.insert(changeset)
```

最初の行では、`Friends.Person` モジュールから構造体を作成しています。少し前に見たばかりだから覚えているでしょう。次の行では changeset を定義するという新しいことをしています。この changeset は `person` オブジェクトの変更が作られるのを見ることができます。このケースでは、全く変更がないことがわかります。

最後の行では、`person` を挿入するのではなく、`changeset` を挿入しています。`changeset` は `person` とその変更、データベースにはデータが行く前に行われるべきバリデーションルールについて知っています。

```elixir
{:error,
 #Ecto.Changeset<action: :insert, changes: %{},
  errors: [first_name: "can't be blank", last_name: "can't be blank"],
  data: #Friends.Person<>, valid?: false>}
```

最後に挿入を行ったときのように、このコードはタプルを返します。しかし、この場合は問題があること示すためにタプルの最初の要素は `:error` になります。何が起こったかは返ってきた changeset に含まれています。これはパターンマッチをすることが取り出すことができます。

```elixir
{:error, changeset} = Friends.Repo.insert(changeset)
```

`changeset.errors` を行うことでエラーを得ることができます。

```elixir
[first_name: "can't be blank", last_name: "can't be blank"]
```

挿入を行う前にでも、`changeset` それ自体が正しいかを検証できます。

```elixir
changeset.valid?
#=> false
```

この changeset はエラーを持っているので、`people` テーブルには何も挿入されません。

正しいデータでも試してみましょう。

```elixir
person = %Friends.Person{}
changeset = Friends.Person.changeset(person, %{first_name: "Ryan", last_name: "Bigg"})
```

普通の `Friends.Person` 構造体からはじめてみましょう。次に `first_name` と `last_name` パラメーターが指定された `person` の changeset を作ることができます。この時点で changeset にエラーがあるかどうかを尋ねることができます。


```elixir
changeset.errors
#=> []
```

そして、このデータが正しいかそうでないかを尋ねることができます。

```elixir
changeset.valid?
#=> true
```

changeset はエラーを持たないため正しいことがわかります。このことから、この changeset を挿入しようとした場合、それは適切に動作します。

```elixir
Friends.Repo.insert(changeset)
#=> {:ok,
     %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: nil,
      first_name: "Ryan", id: 3, last_name: "Bigg"}}
```

`Friends.Repo.insert` がタプルを返すので、`case` を使うことで、何が起こったかによってどのコードを使用するか決めることができます。

```elixir
case Friends.Repo.insert(changeset) do
  {:ok, person} ->
    # do something with person
  {:error, changeset} ->
    # do something with changeset
end
```

**NOTE:** `changeset.valid?` は uniqueness_constraint のような制約のチェックは行いません。このため、データベースに挿入を行ってみてエラーをチェックすることが必要となります。このことから、実際にデータ挿入を行ってみて、`Friends.Repo.insert` の戻り値のタプルを検証することが正しいエラーを得るためのベストプラクティスになるでしょう。挿入する前の changeset はアプリケーションレベルのバリデーションエラーしか含まないからです。

changeset の挿入が成功したら、結果に含まれる `person` をどのようなことにでも利用できます。もし失敗したら、changeset を参照してそのエラーを見ましょう。失敗の場合、エンドユーザーにそれを表示したいかもしれません。changeset のエラーは次のようなキーワードのリストです。


```elixir
[first_name: {"can't be blank", []},
 last_name: {"can't be blank", []}]
```

タプルの最初の要素はバリデーションメッセージで、次の要素がバリデーションメッセージに対するオプションのキーワードのリストです。`validate_required/3` バリデーションはオプションを返しませんが、他の `validate_length/3` のようなメソッドは返します。`bio` というバリデーションをしていたフィールドがあり、そのフィールドが15文字以上でなければいけないとしましょう。これに大しては次のコードが返されます。


```elixir
[first_name: {"can't be blank", []},
 last_name: {"can't be blank", []},
 bio: {"should be at least %{count} characters", [count: 15]}]
```

人が見るのに優しい方法でメッセージを表示させるには、`Ecto.Changeset.traverse_errors/2` を使うことができます。


```elixir
traverse_errors(changeset, fn {msg, opts} ->
  Enum.reduce(opts, msg, fn {key, value}, acc ->
    String.replace(msg, "%{#{key}}", to_string(value))
  end)
end)
```

これは上で表示されたエラーに対して次のコードを返します。

```elixir
%{
  first_name: ["can't be blank"],
  last_name: ["can't be blank"],
   bio: ["should be at least 15 characters"],
}
```

最後に言いたいことは、`Friends.Repo.insert!/2` を使うことで例外を引き起こすことができるということです。もし、変更が正しくない場合、`Ecto.InvalidChangesetError` 例外が発生します。例を次に示します。

```
Friends.Repo.insert! Friends.Person.changeset(%Friends.Person{}, %{first_name: "Ryan"})

** (Ecto.InvalidChangesetError) could not perform insert because changeset is invalid.

* Changeset changes

%{first_name: "Ryan"}

* Changeset params

%{"first_name" => "Ryan"}

* Changeset errors

[last_name: "can't be blank"]

    lib/ecto/repo/schema.ex:111: Ecto.Repo.Schema.insert!/4
```

この例外は変更と変更がどのように間違っているかを表示しています。これはデータを挿入したいときに役立ち、データが正しく挿入できない場合は例外を発生させます。

これでデータベースへのデータの挿入をすることができるようになりました。次にデータをどのように取り出すかを見ていきましょう。

## 最初のクエリ

Ectoによるデータベースにへの問い合わせは二つのステップを必要とします。クエリを組み立て、リポジトリにクエリを渡して実行します。これをする前に、アプリのためにデータベースを再作成し、いくつかのテストデータをセットアップしましょう。データベースを再作成するためには、次のコマンドを実行します。

```
mix ecto.drop
mix ecto.create
mix ecto.migrate
```

そして、テストデータを作るために、`iex -S mix` セッションで次のコードを実行します。

```elixir
people = [
  %Friends.Person{first_name: "Ryan", last_name: "Bigg", age: 28},
  %Friends.Person{first_name: "John", last_name: "Smith", age: 27},
  %Friends.Person{first_name: "Jane", last_name: "Smith", age: 26},
]

Enum.each(people, fn (person) -> Friends.Repo.insert(person) end)
```

このコードはデータベースに、Ryan、John、Janeの三つの people を作成します。データを検証するのに changeset が使えますが、今回はしていません。

次のセクションでは people に足して問い合わせを行いましょう。さぁ次へ！

### 単一レコードの取り出し

`people` テーブルから一つのレコードを取り出すことから始めましょう。

```elixir
Friends.Person |> Ecto.Query.first
```

このコードは次のような `Ecto.Query` を作り出します。

```
#Ecto.Query<from p in Friends.Person, order_by: [asc: p.id], limit: 1>
```
　　
角カッコ `<...>` の間のコードは組み立てられた Ecto クエリを表しています。次のようなほとんど同じようなシンタックスでもこのクエリを組み立てることができます。

```elixir
require Ecto.Query
Ecto.Query.from p in Friends.Person, order_by: [asc: p.id], limit: 1
```

マクロを有効にするため `require Ecto.Query` を必要とします。`Ecto.Query` の `from` を呼び出し、角カッコの間を渡します。ここで見ているように、`Ecto.Query.first` を使うことで `order` と `limit` を使わなくても済みます。

このクエリを実行するためには、`Friends.Repo.one` を呼び出します。

```elixir
Friends.Person |> Ecto.Query.first |> Friends.Repo.one
```

`one` 関数はデータベースから一つだけレコードを取り出し、`Friends.Person` モジュール内の新しい構造体を返します。

```elixir
%Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 28,
 first_name: "Ryan", id: 1, last_name: "Bigg"}
```

`first` も同様で、`last` という関数もあります。

```elixir
Friends.Person |> Ecto.Query.last |> Friends.Repo.one
#=> %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 26,
     first_name: "Jane", id: 3, last_name: "Smith"}
 ```

`Ecto.Repo.one` 関数はデータベースのレコードが一つだけならば、一つ構造体を返します。一つ以上レコードがあったら、`Ecto.MultipleResultsError` 例外が投げられます。次のコードはその問題を引き起こします。

```elixir
Friends.Person |> Friends.Repo.one
```

`Ecto.Query.first` がなく、クエリに対して実行される `limit` や `order` 句もありません。デバッグログで実行されるクエリを見ることができます。

```
[timestamp] [debug] SELECT p0."id", p0."first_name", p0."last_name", p0."age" FROM "people" AS p0 [] OK query=1.8ms
```

このすぐ後に `Ecto.MultipleResultsError` 例外が発生します。

```
** (Ecto.MultipleResultsError) expected at most one result but got 3 in query:

from p in Friends.Person

    lib/ecto/repo/queryable.ex:67: Ecto.Repo.Queryable.one/4
```

これは Ecto が複数のレコードがあると探しているレコードが不明であるために起こります。Ecto は探しているものが明示的なクエリにのみ結果を返します。

クエリにマッチするレコードがない場合は、`one` は `nil` を返します。

### Fetching all records
### 全レコードの取り出し

スキーマから全てのレコードを取り出すために、Ecto は `all` 関数を持っています。

```elixir
Friends.Person |> Friends.Repo.all
```

これは、`people` テーブルに現在入っているレコードを `Friends.Person` 構造体形式で返します。

```elixir
[%Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 28,
  first_name: "Ryan", id: 1, last_name: "Bigg"},
 %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 27,
  first_name: "John", id: 2, last_name: "Smith"},
 %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 26,
  first_name: "Jane", id: 3, last_name: "Smith"}]
```

### IDをもとにした単一レコードの取り出し

ID をもとにレコードを取り出すときは `get` 関数を使います。

```elixir
Friends.Person |> Friends.Repo.get(1)
%Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 28,
 first_name: "Ryan", id: 1, last_name: "Bigg"}
```

### 特定の属性をもとにした単一レコードの取り出し

`id` 以外の属性をもとにレコードを取り出したい場合は、`get_by` 関数を使うことができます。

```elixir
 Friends.Person |> Friends.Repo.get_by(first_name: "Ryan")
 %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 28,
  first_name: "Ryan", id: 1, last_name: "Bigg"}
```

### フィルタリング

特定の属性にマッチする複数のレコードを取り出すためには `where` が使えます。

```elixir
Friends.Person |> Ecto.Query.where(last_name: "Smith") |> Friends.Repo.all
```

```elixir
[%Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 27,
  first_name: "John", id: 2, last_name: "Smith"},
 %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 26,
  first_name: "Jane", id: 3, last_name: "Smith"}]
```

もし、末尾の `Friends.Repo.all` がない場合、Ecto が次のクエリを生成するのがわかるでしょう。

```
#Ecto.Query<from p in Friends.Person, where: p.last_name == "Smith">
```

同じレコードを取り出すのにこのクエリシンタックスを使うこともできます。


```elixir
Ecto.Query.from(p in Friends.Person, where: p.last_name == "Smith") |> Friends.Repo.all
```

どちらのクエリシンタックスについてもピン演算子(`^`)を使って、ピンされた変数を必要とします。

```elixir
last_name = "Smith"
Friends.Person |> Ecto.Query.where(last_name: last_name) |> Friends.Repo.all
```

```
** (Ecto.Query.CompileError) variable `last_name` is not a valid query expression.
  Variables need to be explicitly interpolated in queries with ^
             expanding macro: Ecto.Query.where/2
             iex:1: (file)
    (elixir) expanding macro: Kernel.|>/2
             iex:1: (file)
```

より長いクエリシンタックスでも同じことが起こります。

```elixir
Ecto.Query.from(p in Friends.Person, where: p.last_name == last_name) |> Friends.Repo.all
```

```
** (Ecto.Query.CompileError) variable `last_name` is not a valid query expression. 
  Variables need to be explicitly interpolated in queries with ^
             expanding macro: Ecto.Query.where/3
             iex:1: (file)
             expanding macro: Ecto.Query.from/2
             iex:1: (file)
    (elixir) expanding macro: Kernel.|>/2
             iex:1: (file)
```

これを実行してデータを取り出すには、ピン演算子(`^`)を使います。

```elixir
last_name = "Smith"
Friends.Person |> Ecto.Query.where(last_name: ^last_name) |> Friends.Repo.all
```

もしくは以下のように、

```elixir
last_name = "Smith"
Ecto.Query.from(p in Friends.Person, where: p.last_name == ^last_name) |> Friends.Repo.all
```

ピン演算子はクエリビルダーにSQLインジェクション対策が施されたパラメーター化されたSQLクエリを使うようにします。

### Ectoクエリの組み立て

Ectoクエリは一つの場所で組み立てる必要はありません。すでに存在するクエリから `Ecto.Query` 関数を呼び出すことでクエリを作ることができます。例えば、名前が "Smith" である全ての人を見つけたいとしましょう。次のようにできます。

```elixir
query = Friends.Person |> Ecto.Query.where(last_name: "Smith") 
```

苗字が "Jane" の人だけにスコープを絞りたいならば、次のようにできます。

```elixir
query = query |> Ecto.Query.where(first_name: "Jane")
```

クエリはこの時点で二つの `where` 句を持つことになります。

```
#Ecto.Query<from p in Friends.Person, where: p.last_name == "Smith",
 where: p.first_name == "Jane">
```

これは最初のクエリで何か作業をしてから、その後でそのクエリを使って別なクエリを構築するのに役立ちます。

## レコードの更新

レコードを Ecto で更新するには、最初にデータベースからレコードを取り出す必要があります。その後で、レコードから changeset とレコードに対する変更を構成し、`Ecto.Repo.update` 関数を呼び出します。

データベースから最初の person レコードを取り出し、年齢(age)を変更してみましょう。最初に person を取り出します。

```elixir
person = Friends.Person |> Ecto.Query.first |> Friends.Repo.one
```

次に、changeset を作ります。単に新しい年齢(age)を持った新しい `Friends.Person` 構造体を作るので、changeset が必要になります。Ecto はデータベースとの連携なしでは年齢が変更されるかを知ることができないかもしれません。changeset を作ってみましょう。


```elixir
changeset = Friends.Person.changeset(person, %{age: 29})
```

changeset はデータベースに年齢が29にするためにレコードを更新したいことを知らせます。変更についてデータベースとやり取りするために、次のコマンドを実行します。

```elixir
Friends.Repo.update(changeset)
```

`Friends.Repo.insert` と同じように、`Friends.Repo.update` はタプルを返します。

```elixir
{:ok,
 %Friends.Person{__meta__: #Ecto.Schema.Metadata<:loaded>, age: 29,
  first_name: "Ryan", id: 1, last_name: "Bigg"}}
```

何かの理由で changeset が失敗したら、`Friends.Repo.update` の結果は `{:error, changeset}` になります。これは `first_name` が空になるように changeset のパラメーターを変えることで引き起こすこともできます。

```elixir
changeset = Friends.Person.changeset(person, %{first_name: ""})
#=> {:error,
     #Ecto.Changeset<action: :update, changes: %{first_name: ""},
      errors: [first_name: "can't be blank"], data: #Friends.Person<>,
      valid?: false>}
```

このことは `update` 関数からの結果によって異なったコードを実行するのに、`case` ステートメントを使えるということを意味しています。

```elixir
case Friends.Repo.update(changeset) do
  {:ok, person} ->
    # do something with person
  {:error, changeset} ->
    # do something with changeset
end
```

`insert!` と同じように、changeset に問題がある場合に例外を引き起こす `update!` 関数があります。

```
changeset = Friends.Person.changeset(person, %{first_name: ""})
Friends.Repo.update! changeset

** (Ecto.InvalidChangesetError) could not perform update because changeset is invalid.

* Changeset changes

%{first_name: ""}

* Changeset params

%{"first_name" => ""}

* Changeset errors

[first_name: {"can't be blank", []}]

    lib/ecto/repo/schema.ex:132: Ecto.Repo.Schema.update!/4
```

## レコードの削除

レコードの作成(`insert`)・読み込み(`get`, `get_by`, `where`)・更新についてカバーしました。このガイドの最後に行ったのは Ecto を使ったレコードの削除についてでした。

更新と同じように、レコードを削除するには、最初にデータベースからレコードを取り出し、`Friends.Repo.delete` を呼び出します。

```elixir
person = Friends.Repo.get(Friends.Person, 1)
Friends.Repo.delete(person)
{:ok,
 %Friends.Person{__meta__: #Ecto.Schema.Metadata<:deleted>, age: 29,
  first_name: "Ryan", id: 2, last_name: "Bigg"}}
```

`insert` や `update` と同じように、`delete` はタプルを返します。削除が完了したらタプルの最初の要素は `:ok`、失敗したら `:error` になります。