3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

primary key用のEcto.Changeset.unique_constraintラッパーを書いた

Last updated at Posted at 2018-03-28

まとめ

  • 複合primaryキーでも単数でもindex名としては:PRIMARYなので書き方は同じ
  • primaryキーにunique_constraintを使ったときのエラー表示が分かりにくいので、ラッパーを書いた

調査

調査用スキーマ

  @primary_key false
  schema "profiles" do
    field :user_id, :integer, primary_key: true
    field :email,   :string, primary_key: true
    field :token,   :string, primary_key: true
  end

Primaryキーのconstraintの書き方

単数でも複合でもindex名は:PRIMAYなので書き方は同じです。
changeset |> Changeset.unique_constraint(:user_id, [name: :PRIMARY])

調査結果

エラーメッセージがわかりにくい

changeset.errors #=> [user_id: {"has already been taken", []}]

primaryキーはuser_id, email, tokenなのにuser_idについてしか言及されていない。

エラーメッセージを変更する

Changeset.unique_constraintの第2引数に渡すfield名は、デフォルトindex名の生成とerrorsのキー名にしか使われていないように見えるため、nameオプションでindex名を指定している場合は好きな名前を指定できそうです。

changeset |> Changeset.unique_constraint(:primary_keys, [name: :PRIMARY])
changeset.errors #=> [primary_keys: {"has already been taken", []}]

しかし慣例として、field名を入れたほうが良さそうに見えます。
documentには以下のように記載されており、実装も変数名はfieldとなっています。

Notice that the first param is just one of the unique index fields, this will be used as the error key to the changeset errors keyword list.

このため、ライブラリ側が想定していない使い方は控え、messageオプションに全ての対象field名を記載することにしました。

primary_constraintの実装

目標

  • 調査用スキーマを使って、以下のエラーメッセージを得る
    • errorsのキー名は複合キーの先頭field

# changeset.errors => [user_id: {"Duplicate primary key [:user_id, :email, :token]", []}]

# 使い方
def changeset(struct, params \\ %{}) do
  struct
  |> Changeset.cast(params, @required_fields)
  |> primary_constraint() 
end

実装

  defmacro primary_constraint(changeset) do
    quote do
      alias Ecto.Changeset
      pkeys = __MODULE__.__schema__(:primary_key)
      first_field = hd pkeys
      Changeset.unique_constraint(unquote(changeset), first_field, [name: :PRIMARY, message: "Duplicate primary key #{inspect(pkeys)}"])
    end
  end

以上です。プロダクトに投入して使っています。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?