因此,我试图了解迁移在Ecto中的工作原理。通过这个我不是说如何使用它们但是代码中实际发生了什么。我所看到的是,当运行各种宏时,状态被泵入代理。
运行混合任务以迁移数据时,将检索代理数据并运行相应的SQL命令。
这让我感到震惊,我不明白编译过程中代理进程是如何活跃的。好的,所以我有点明白,在宏扩展期间,可以运行引用块之外的任何代码,包括产生进程,但为什么在编译/扩展和实际执行期间仍还活着?
克里斯
答案 0 :(得分:1)
我不明白编译过程中代理进程是如何活动的。
不是。宏将DSL转换为调用Ecto.Migration
和Ecto.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扩展到此代码。