Elixirの軽量なORMであるEcto
それの使いかたをざっと把握していくために少しEctoを触ってみました。
メモです。
対象
defmodule DeviceManager.Device do
use DeviceManager.Web, :model
schema "devices" do
field :device_name, :string
field :device_type, :string
field :os, :string
field :os_version, :string
field :description, :string
timestamps
end
@required_fields ~w(device_name device_type os os_version)
@optional_fields ~w(description)
def changeset(model, params \\ :empty) do
model
|> cast(params, @required_fields, @optional_fields)
end
end
標準的なクエリ
DeviceManager.Device |> Ecto.Query.select([q], q.device_name) |> Ecto.Query.where([q], q.id == 1) |> DeviceManager.Repo.all
とか
DeviceManager.Device |> Ecto.Query.where([q], q.id == 1) |> Ecto.Query.select([q], q.device_name) |> DeviceManager.Repo.all
これらはいずれも、以下のようなクエリが発行される。
SELECT d0."device_name" FROM "devices" AS d0 WHERE (d0."id" = 1) [] OK query=1.3ms
パイプで接続されたEcto.Queryはクエリを結合していくのですね。
他、以下のようにlimitをかけることも可能。
DeviceManager.Device |> Ecto.Query.select([q], q.device_name) |> where([q], q.id == 2) |> limit([q], 1) |> DeviceManager.Repo.all
preloadを行う
belongs_to などで関係を持った、異なるテーブルに対してクエリを投げる場合、以下のようにpreloadを使います。
> DeviceManager.User |> DeviceManager.Repo.all |> DeviceManager.Repo.preload [:device] > DeviceManager.User |> Ecto.Query.preload(:device) |> Ecto.Query.select([q], q) |> DeviceManager.Repo.all
Ecto.Repo#preload/2 は、以下の通り IN で統合したテーブルに対してクエリを投げるのですね。この時に発行されるクエリは以下。
[debug] SELECT u0."id", u0."user_name", u0."user_sex", u0."device_id", u0."inserted_at", u0."updated_at" FROM "users" AS u0 [] OK query=1.1ms [debug] SELECT d0."id", d0."device_name", d0."device_type", d0."os", d0."os_version", d0."description", d0."inserted_at", d0."updated_at" FROM "devices" AS d0 WHERE (d0."id" IN ($1,$2)) [1, 2] OK query=1.0ms
なるほど。