どうも、靖宗です。
今回はEcto、ということでデータベースラッパーのお話でしょうか。
Elixirでよく使われるライブラリなので個別に触りたいところでもありますが、とりあえず今回はPhoenixのドキュメントを読み進めます。
Ecto
ウェブシステムを開発する上で避けられないのがデータベース絡みのお話です。
(とはいえFirebaseなど便利なものも出てきているので、薄ぼんやりとした理解でもある程度のものができてしまう時代だとは思います。)
Ectoは現在
- PostgreSQL
- MySQL
- MSSQL
- SQLite
- Mnesia
の5つのRDBMSに対応してるそうです。Mnesiaなんかは初耳です。
特に何も指定しない場合はPhoenixはPostgreSQLをチョイスします。
Hello, Ecto
開発用のPostgreSQL
最初のUp and Runningでも触れましたが開発用のデータベースの設定はconfig/dev.exs
に記載されてます。ユーザー名や参照先を変更したい場合はこのファイルを編集します。
デフォルトでは参照先はlocalhost
、ユーザー名はpostgres
、パスワードはpostgres
となっています。このpostgres
のユーザーを作成するにはpsql
コマンドでrootユーザーとしてログインした後下記のコマンドで作成できます。
CREATE USER postgres; ALTER USER postgres PASSWORD 'postgres'; ALTER USER postgres WITH SUPERUSER;
簡単に触ってみる
とりあえずなんか動かしてみます。mix phx.gen.schema
でEctoのスキーマを作成できるそうです。
EctoのスキーマはElixirのデータタイプをPostgreSQLのテーブルへと変換するルールのようなものでしょうか。
とりあえずドキュメントどおりやってみます。
PS \hello_phoenix> mix phx.gen.schema User users name:string email:string bio:string number_of_pets:integer * creating lib/hello_phoenix/user.ex * creating priv/repo/migrations/20190321014808_create_users.exs Remember to update your repository by running migrations: $ mix ecto.migrate
ファイルが2個生成され、始めてlib/hello_phoenix/
の方にファイルができました。なんか嬉しい。
1個目は先ほど定義したスキーマの情報が記載されています。2個目は名前や中身的に現在のデータベースに先ほど定義した情報のテーブルを作成するための記述でしょう。ORMとかでよくありそうな感じです。
スキーマを登録したらマイグレーション(データベース作ったりリレーションの整合性とったりとか)が必要な筈です。もしmix ecto.create
してなければおそらくそちらでスキーマの取り込みまで実行されると思いますが、基本的に開発中にどんどん追加していくと思いますので、mix ecto.migrate
でマイグレーションします。
PS \hello_phoenix> mix ecto.migrate Compiling 1 file (.ex) Generated hello_phoenix app [info] == Running 20190321014808 HelloPhoenix.Repo.Migrations.CreateUsers.change/0 forward [info] create table users [info] == Migrated 20190321014808 in 0.0s
データベースにusersのテーブルが作成されているか確認します。
自分はdockerでpostgresを動かしてるのでdockerから確認します。
PS \hello_phoenix> docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES c1b71c3bc403 postgres "docker-entrypoint.s…" 3 weeks ago Up 3 days 0.0.0.0:5432->5432/tcp ph_psql PS \hello_phoenix> docker exec -it ph_psql /bin/bash root@c1b71c3bc403:/# psql -U elixir psql (10.5 (Debian 10.5-1.pgdg90+1)) Type "help" for help. elixir=# \connect hello_phoenix_dev You are now connected to database "hello_phoenix_dev" as user "elixir". hello_phoenix_dev=# \d List of relations Schema | Name | Type | Owner --------+-------------------+----------+-------- public | schema_migrations | table | elixir public | users | table | elixir public | users_id_seq | sequence | elixir (3 rows)
テーブル作成されていることが確認できます。
usersだけでなくusers_id_seqというテーブルもできていますが、コレはusersのシーケンスだそうです。いままでDjangoなどのORMに頼りっきりでPostgreSQL使ってるのにシーケンスという概念を知りませんでしたが、どうやらユニークなIDを生成するオブジェクトだそうで、ユーザー情報を生成するときに連番の番号を高速に生成して登録したり検索の時によしなにしてくれるもんだと思っておけばいいんじゃないでしょうか(適当)
一応usersの中身も見ておきます。
hello_phoenix_dev=# \d users Table "public.users" Column | Type | Collation | Nullable | Default ----------------+--------------------------------+-----------+----------+----------------------------------- id | bigint | | not null | nextval('users_id_seq'::regclass) name | character varying(255) | | | email | character varying(255) | | | bio | character varying(255) | | | number_of_pets | integer | | | inserted_at | timestamp(0) without time zone | | not null | updated_at | timestamp(0) without time zone | | not null | Indexes: "users_pkey" PRIMARY KEY, btree (id)
idは先ほど説明したシーケンスの物なのでいいとして、inserted_at
とupdated_at
が着いてます。(ORM使いまくりマンとしては有り難いです)
これは先ほどmix phx.gen.schema
で生成された一個目のファイルusers.ex
に記載があります。
... schema "users" do field :bio, :string field :email, :string field :name, :string field :number_of_pets, :integer timestamps() end ...
この辺をカスタマイズしたい欲求はあまり無いと思いますが、変更するならこの辺をいじるっぽいです。
プライマリキーを変更する方法はまだ特に記載がありませんが、基本デフォルトでいい気はします。
The Repo
Phoenixでアプリケーションを生成した際に生成されるファイルlib/hello_phoenix/repo.ex
に関してです。
中身は非常にシンプルでものの数行しかありません。
defmodule HelloPhoenix.Repo do use Ecto.Repo, otp_app: :hello_phoenix, adapter: Ecto.Adapters.Postgres end
生成したプロジェクトでEctoを使うで!アダプターはPostgresで!ってぐらいの役割なのでほとんど編集することは無いと思います。
あるとするならPostgreSQL以外の選択肢をチョイスした場合にアダプターを変更するぐらいでしょうか?
あとデータベースの設定はconfig/dev.exs
を編集しましたが、必要に応じてテスト用の設定config/test.exs
やデプロイ用の設定config/prod.secret.exs
を編集するようです。
The Schema
一番最初にスキーマの作成をしましたが、EctoのスキーマはElixirのデータ構造とデータベースのテーブルを繋ぐ(変換する)役割を果たしています。
上記の例ではlib/hello_phoenix/user.ex
にスキーマが作成されています。
defmodule HelloPhoenix.User do use Ecto.Schema import Ecto.Changeset schema "users" do field :bio, :string field :email, :string field :name, :string field :number_of_pets, :integer timestamps() end @doc false def changeset(user, attrs) do user |> cast(attrs, [:name, :email, :bio, :number_of_pets]) |> validate_required([:name, :email, :bio, :number_of_pets]) end end
どうやらスキーマで定義した型は構造体として利用できるそうです。
データのキャストからバリデーションもこのスキーマのモジュールが担ってくれるようなので、開発している際はバリデーションをいちいち書く必要は無さそうです。
一旦この辺で区切ります。
次回はChangesetsやValidationsのお話。リレーションを貼ったりする方法とかあるのかな