Elixir宏与代理状态

时间:2017-10-04 10:07:26

标签: macros elixir ecto

因此,我试图了解迁移在Ecto中的工作原理。通过这个我不是说如何使用它们但是代码中实际发生了什么。我所看到的是,当运行各种宏时,状态被泵入代理。

运行混合任务以迁移数据时,将检索代理数据并运行相应的SQL命令。

这让我感到震惊,我不明白编译过程中代理进程是如何活跃的。好的,所以我有点明白,在宏扩展期间,可以运行引用块之外的任何代码,包括产生进程,但为什么在编译/扩展和实际执行期间还活着?

克里斯

1 个答案:

答案 0 :(得分:1)

  

我不明白编译过程中代理进程是如何活动的。

不是。宏将DSL转换为调用Ecto.MigrationEcto.Migration.Runner中的函数的代码。这是一个例子。以下迁移:

defmodule M.Repo.Migrations.CreatePosts do
  use Ecto.Migration

  def change do
    create(:posts) do
      add :title, :string
      add :content, :text
    end
  end
end

编译成这个Erlang:

-module('Elixir.M.Repo.Migrations.CreatePosts').

...

change() ->
    _@1 = #{'__struct__' := 'Elixir.Ecto.Migration.Table'} =
          posts,
    'Elixir.Ecto.Migration.Runner':start_command({create,
                          'Elixir.Ecto.Migration':'__prefix__'(_@1)}),
    case case _@1 of
       #{primary_key := _@2} -> _@2;
       _@2 when erlang:is_map(_@2) ->
           erlang:error({badkey, primary_key, _@2});
       _@2 -> _@2:primary_key()
     end
    of
      _@3 when (_@3 =:= nil) or (_@3 =:= false) ->
      _@4 = nil, nil;
      _ ->
      _@4 =
          'Elixir.Ecto.Migration.Runner':repo_config(migration_primary_key,
                             []),
      'Elixir.Ecto.Migration':add(case
                    'Elixir.Access':get(_@4, name, nil)
                      of
                    _@5
                        when (_@5 =:= nil) or
                           (_@5 =:= false) ->
                        id;
                    _@6 -> _@6
                      end,
                      case 'Elixir.Access':get(_@4, type, nil)
                      of
                    _@7
                        when (_@7 =:= nil) or
                           (_@7 =:= false) ->
                        bigserial;
                    _@8 -> _@8
                      end,
                      [{primary_key, true}])
    end,
    'Elixir.Ecto.Migration':add(title, string),
    'Elixir.Ecto.Migration':add(content, text),
    'Elixir.Ecto.Migration.Runner':end_command(),
    _@1.

即使您没有阅读Erlang,您也可以确定它正在调用Ecto.Migration.Runner.start_command,然后调用向代理添加数据的函数,然后最终调用{{1} }。所有这些都在运行时在执行迁移时发生,而不是在编译时发生。在编译时,只有DSL扩展到此代码。