繁体   English   中英

带有状态代理的 Elixir 宏

[英]Elixir macro with Agent for state

所以我试图了解迁移在 Ecto 中是如何工作的。 我的意思不是如何使用它们,而是在代码中实际发生了什么。 我看到的是,当运行各种宏时,状态会被泵入代理。

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

这让我大吃一惊,我不明白在编译期间代理进程是如何活动的。 好的,所以我有点理解在宏扩展期间,可以运行引用块之外的任何代码,包括生成过程,但为什么在编译/扩展后和实际执行期间它仍然存在?

克里斯

我不明白在编译期间代理进程是如何活动的。

不是。 宏将 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 ,然后调用了给agent添加数据的函数,最后调用了.end_command 所有这些都发生在执行迁移时的运行时,而不是编译时。 在编译时,仅将 DSL 扩展为此代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM