2016-02-06 7 views
11

で列挙型を、我々はこのような何かを行うことができます。Ecto's official docからはPostgresの使用方法のPostgreSQLではエクト

CREATE TYPE order_status AS ENUM ('placed','shipping','delivered') 

は、Postgresのマップするネイティブな型が存在しない列挙型を。このmoduleは、列挙型構造のカスタムタイプを提供しますが、データベースの整数にマップします。私は簡単にそのライブラリを使用することができますが、データベースに同梱されているネイティブの列挙型を使用することをお勧めします。

エクトもcustom typesを作成する方法を提供していますが、私の知る限り、カスタムタイプがネイティブエクト型にマップする必要があり、これはエクトとスキーマで行うことができるかどうか...

誰もが知っています?はいの場合、移行はどのように機能しますか?

答えて

5

postgresqlの列挙型ごとにEctoタイプを作成する必要があります。スキーマ定義では、タイプは:stringである必要があります。マイグレーションでは、タイプをモジュール名に設定します。しかし、これは本当に退屈得ることができますので、私はPostgreSQLの列挙型を使用しています私のプロジェクトでは、以下のマクロがあります。

defmodule MyDB.Enum do 

    alias Postgrex.TypeInfo 

    defmacro defenum(module, name, values, opts \\ []) do 
    quote location: :keep do 
     defmodule unquote(module) do 

     @behaviour Postgrex.Extension 

     @typename unquote(name) 
     @values unquote(values) 

     def type, do: :string 

     def init(_params, opts), do: opts 

     def matching(_), do: [type: @typename] 

     def format(_), do: :text 

     def encode(%TypeInfo{type: @typename}=typeinfo, str, args, opts) when is_atom(str), do: encode(typeinfo, to_string(str), args, opts) 
     def encode(%TypeInfo{type: @typename}, str, _, _) when str in @values, do: to_string(str) 
     def decode(%TypeInfo{type: @typename}, str, _, _), do: str 

     def __values__(), do: @values 

     defoverridable init: 2, matching: 1, format: 1, encode: 4, decode: 4 

     unquote(Keyword.get(opts, :do, [])) 
     end 
    end 
    end 

end 

可能な使用:

import MyDB.Enum 
defenum ColorsEnum, "colors_enum", ~w"blue red yellow" 

ColorsEnumがモジュール名となり、"colors_enum"になりますPostgresqlのenum name internal:データベース移行で列挙型を作成するために文を追加する必要があります。最後の引数はenum値のリストです。 ~w sigilを使用して、文字列を空白で分割して、これがどれくらい簡潔であるかを示しました。また、Ectoスキーマを通過するときに原子値を文字列値に変換する節を追加しました。

+0

あなたの答えをありがとう!これは有望ですが、私はスキーマでColorsEnumを使用する方法がわかりません。 (私は移行部分を取得します)。スキーマにフィールドを追加すると、どのタイプを使用しますか? ':string'? –

+0

はい、実際のスキーマ定義には ':string'を使うべきです。 'postgrex'がEnum型を必要とする理由は、内部PostgreSQL' oid'をこの場合は文字列であるElixir型にマップするからです。 – asonge

+0

@ason​​ge私はあなたのElixir Fuを尊敬していますが、私は個人的にpostgresqlの列挙型ごとにEctoタイプは必要ありません。たぶん私はsthが不足しているが、なぜあなたはそれを必要とするだろうか?文字列とチェンジセットバリデーターを使用するだけです。https://hexdocs.pm/ecto/Ecto.Changeset.html#validate_inclusion/4 –

22

は、たぶん私は何か間違ったことをしましたが、私はちょうどこのようなタイプとフィールド作成:

# creating the database type 
execute("create type post_status as enum ('published', 'editing')") 

# creating a table with the column 
create table(:posts) do 
    add :post_status, :post_status, null: false 
end 

をしてからちょうどフィールドの文字列行わ:

field :post_status, :string 

をし、動作しているようです。

+10

フレームワークの新しさについては、JustMichaelのソリューションが機能しますが、コードをどこに置く必要があるのか​​を追加すると思いました。最初のコードセクションは、 '' change do''ブロックの中のマイグレーションファイルにあります。 2番目のブロックはモデルファイルの '' 'schema do'''ブロックの内側にあります。 – jeffreymatthias

+1

'published'や' editing'以外の文字列を渡すとどうなりますか?どのような種類のエラーが発生しますか? –

+1

@TerenceChow DBはおそらく何かを上げ、DB操作は失敗します。 – JustMichael

7

@JustMichaelの小さな機能強化。あなたがロールバックする必要がある場合は、使用することができます。

def down do 
    drop table(:posts) 
    execute("drop type post_type") 
end 
+0

はい!いい視点ね! –

3

をサポートしています...私たちはエクトを持っているエクト2.2.6のよう.Migration.execute/2これはupとdownのargをとります。 changeブロック内の当社の移行ファイルで

execute("create type post_status as enum ('published', 'editing')", "drop type post_status")

を、そしてエクトは効果的にロールバックすることができるようになります。だから我々は行うことができます。

関連する問題