[英]Elixir macro with Agent for state
所以我试图了解迁移在 Ecto 中是如何工作的。 我的意思不是如何使用它们,而是在代码中实际发生了什么。 我看到的是,当运行各种宏时,状态会被泵入代理。
当运行混合任务以迁移数据时,将检索代理数据并运行适当的 SQL 命令。
这让我大吃一惊,我不明白在编译期间代理进程是如何活动的。 好的,所以我有点理解在宏扩展期间,可以运行引用块之外的任何代码,包括生成过程,但为什么在编译/扩展后和实际执行期间它仍然存在?
克里斯
我不明白在编译期间代理进程是如何活动的。
不是。 宏将 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
,然后调用了给agent添加数据的函数,最后调用了.end_command
。 所有这些都发生在执行迁移时的运行时,而不是编译时。 在编译时,仅将 DSL 扩展为此代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.