2017-01-31 20 views
1

私はすべてのモデルでtimestampsを利用するphoenix appを持っています。Elixir Phoenix - タイムスタンプに列を追加

created_at  (utc datetime) 
updated_at  (utc datetime) 
created_at_utc (utc timestamp of created_at field) 
updated_at_utc (utc timestamp of updated_at field) 

どのように私は、タイムスタンプ機能を拡張(または新しいものを生成する)ことができ、自動的にこれらのフィールドを生成する:しかし、私は私がモデルにtimestampsを含めいつでも、それは次のフィールドが追加されるようにタイムスタンプを拡張したいですか?

UPDATE 私は下図のように私のヘルパーdb_helpers.exにEcto.SchemaとEcto.Migrationsモジュールを拡張しようとしてきた答えで示唆したように:

defmodule Extension do 
    defmacro extends(module) do 
    module = Macro.expand(module, __CALLER__) 
    functions = module.__info__(:functions) 

    signatures = Enum.map functions, fn { name, arity } -> 
     args = Enum.map 0..arity, fn(i) -> 
     { String.to_atom(<< ?x, ?A + i >>), [], nil } 
     end 

     { name, [], tl(args) } 
    end 

    quote do 
     defdelegate unquote(signatures), to: unquote(module) 
     defoverridable unquote(functions) 
    end 
    end 
end 


defmodule Ecto.Schema do 
    import Extension 

    extends Ecto.Schema 

    @doc """ 
     Generates `:inserted_at` and `:updated_at` timestamp fields. 
     The fields generated by this macro will automatically be set to 
     the current time when inserting and updating values in a repository. 
     ## Options 
     * `:type` - the timestamps type, defaults to `:naive_datetime`. 
     * `:type_utc` - the utc timestamps type, defaults to `:utc_datetime`. 
     * `:usec` - sets whether microseconds are used in timestamps. 
      Microseconds will be 0 if false. Defaults to true. 
     * `:created_at` - the name of the column for insertion times or `false` 
     * `:updated_at` - the name of the column for update times or `false` 
     * `:created_at_utc` - the name of the column for utc insertion times or `false` 
     * `:updated_at_utc` - the name of the column for utc update times or `false` 
     * `:autogenerate` - a module-function-args tuple used for generating 
      both `inserted_at` and `updated_at` timestamps 
     All options can be pre-configured by setting `@timestamps_opts`. 
    """ 
    defmacro timestamps(opts \\ []) do 
    quote bind_quoted: binding() do 
     timestamps = 
     [created_at: :created_at, updated_at: :updated_at, 
     created_at_utc: :created_at_utc, inserted_at_utc: :inserted_at_utc, 
     type: :naive_datetime, type_utc: :utc_datetime, 
     usec: true] 
     |> Keyword.merge(@timestamps_opts) 
     |> Keyword.merge(opts) 

     type  = Keyword.fetch!(timestamps, :type) 
     type_utc  = Keyword.fetch!(timestamps, :type_utc) 
     precision = if Keyword.fetch!(timestamps, :usec), do: :microseconds, else: :seconds 
     autogen = timestamps[:autogenerate] || {Ecto.Schema, :__timestamps__, [type, precision]} 

     if created_at = Keyword.fetch!(timestamps, :created_at) do 
     Ecto.Schema.field(created_at, type, []) 
     Module.put_attribute(__MODULE__, :ecto_autogenerate, {created_at, autogen}) 
     end 

     if updated_at = Keyword.fetch!(timestamps, :updated_at) do 
     Ecto.Schema.field(updated_at, type, []) 
     Module.put_attribute(__MODULE__, :ecto_autogenerate, {updated_at, autogen}) 
     Module.put_attribute(__MODULE__, :ecto_autoupdate, {updated_at, autogen}) 
     end 

     if created_at_utc = Keyword.fetch!(timestamps, :created_at_utc) do 
     Ecto.Schema.field(created_at_utc, type, []) 
     Module.put_attribute(__MODULE__, :ecto_autogenerate, {created_at_utc, autogen}) 
     end 

     if updated_at_utc = Keyword.fetch!(timestamps, :updated_at_utc) do 
     Ecto.Schema.field(updated_at_utc, type, []) 
     Module.put_attribute(__MODULE__, :ecto_autogenerate, {updated_at_utc, autogen}) 
     Module.put_attribute(__MODULE__, :ecto_autoupdate, {updated_at_utc, autogen}) 
     end 
    end 
    end 
end 

defmodule Ecto.Migration do 
    import Extension 

    extends Ecto.Migration 

    @doc """ 
     Adds `:created_at` and `:updated_at` timestamps columns. 
     Those columns are of `:naive_datetime` type, and by default 
     cannot be null. `opts` can be given to customize the generated 
     fields. 
     ## Options 
     * `:created_at` - the name of the column for insertion times, providing `false` disables column 
     * `:updated_at` - the name of the column for update times, providing `false` disables column 
     * `:created_at_utc` - the name of the column for utc insertion times, providing `false` disables column 
     * `:updated_at_utc` - the name of the column for utc update times, providing `false` disables column 
     * `:type` - column type, defaults to `:naive_datetime` 
     * `:type_utc` - column type for utc, defaults to `:utc_datetime` 
    """ 
    def timestamps(opts \\ []) do 
    opts = Keyword.put_new(opts, :null, false) 

    {type, opts} = Keyword.pop(opts, :type, :naive_datetime) 
    {type_utc, opts} = Keyword.pop(opts, :type_utc, :utc_datetime) 
    {created_at, opts} = Keyword.pop(opts, :created_at, :created_at) 
    {updated_at, opts} = Keyword.pop(opts, :updated_at, :updated_at) 
    {created_at_utc, opts} = Keyword.pop(opts, :created_at_utc, :created_at_utc) 
    {updated_at_utc, opts} = Keyword.pop(opts, :updated_at_utc, :updated_at_utc) 

    if created_at != false, do: add(created_at, type, opts) 
    if updated_at != false, do: add(updated_at, type, opts) 
    if created_at_utc != false, do: add(created_at_utc, type_utc, opts) 
    if updated_at_utc != false, do: add(updated_at_utc, type_utc, opts) 
    end 
end 

しかし、私が実行しようとしますmix ecto.migrate私は、次のエラーを取得しています:すべてのメソッドが利用できるように

== Compilation error on file web/models/accounts.ex == 
** (CompileError) web/models/accounts.ex:4: undefined function schema/2 
    (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6 
    (elixir) lib/kernel/parallel_compiler.ex:117: anonymous fn/4 in Kernel.ParallelCompiler.spawn_compilers/1 

マクロextendsはそれを行うべきではありません。

:あなたは2つのオプションがありhttps://gist.github.com/pavlos/c86858290743b4d4fed9

答えて

0

Extensionモジュールはここから来ていることに注意してください。 timestampsからEcto.Schemaに、そしてtimestampsの機能をEcto.Migrationから、あなたのモデルとマイグレーションでインポートすることを考えてみてください。ソースコードで実装されているのと同じ方法で列を実装してください。

このアプローチは可能性があります:

  • は、ソースコード
  • の優れた知識を実装し、あなたが勝ったことを確認するために困難にするので、より有益で
  • ために掘りや勉強のソースコードを、より多くの時間を要します間違いをしないでください。

timestampsの機能を拡張する代わりに、新しいヘルパーの関数またはマクロを使用してください。それは以下となります。

は、あなたのモデルだけでなく、これらのフィールドを持ちたいというを覚えていますが、データベース内の、どの手段を実装することが容易に

  • 少ない時間と労力
  • を取りますマイグレーションにそれらを追加するか、またはデータベースからの現在の値に基づいてそれらを追加するスクリプトを準備する必要があります。

    +0

    私はスキーマと移行を提案するように拡張しようとしましたが、今回のアップデートで言及されている他の問題が発生しています。何かご意見は? – user2694306

    +0

    延長のアイデアを落とす:) 2.アプローチを使用すると、何かを壊さないように、より速く、より安全になります。 – PatNowak

    関連する問題