[英]Elixir macro with Agent for state
So I am trying to get my head around how migrations work in Ecto.所以我试图了解迁移在 Ecto 中是如何工作的。 By this I dont mean how to use them but what is actually happening in the code.
我的意思不是如何使用它们,而是在代码中实际发生了什么。 What I am seeing is that when various macros are run then state is been pumped into an Agent.
我看到的是,当运行各种宏时,状态会被泵入代理。
When the mix task is run to migrate the data then the Agents data is retrieved and the appropriate SQL commands are ran.当运行混合任务以迁移数据时,将检索代理数据并运行适当的 SQL 命令。
This blows my mind, I dont understand how an Agent process is alive during compilation.这让我大吃一惊,我不明白在编译期间代理进程是如何活动的。 Ok, so I kind of understand that during macro expansion then any code outside of quoted blocks can be ran, including spawning processes but why is it still alive after compilation/expansion and during actual execution?
好的,所以我有点理解在宏扩展期间,可以运行引用块之外的任何代码,包括生成过程,但为什么在编译/扩展后和实际执行期间它仍然存在?
Chris克里斯
I dont understand how an Agent process is alive during compilation.
我不明白在编译期间代理进程是如何活动的。
It isn't.不是。 The macros turn the DSL into code that calls functions in
Ecto.Migration
and Ecto.Migration.Runner
.宏将 DSL 转换为调用
Ecto.Migration
和Ecto.Migration.Runner
函数的代码。 Here's an example.这是一个例子。 The following migration:
以下迁移:
defmodule M.Repo.Migrations.CreatePosts do
use Ecto.Migration
def change do
create(:posts) do
add :title, :string
add :content, :text
end
end
end
compiles into this Erlang:编译成这个 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.
Even if you don't read Erlang, you can figure out that it's calling Ecto.Migration.Runner.start_command
, and then calls functions that add data to the agent, and then finally calls .end_command
.就算不看Erlang,也能看出来是调用了
Ecto.Migration.Runner.start_command
,然后调用了给agent添加数据的函数,最后调用了.end_command
。 All this happens at runtime when the migration is executed, not compile time.所有这些都发生在执行迁移时的运行时,而不是编译时。 At compile time, only the DSL is expanded to this code.
在编译时,仅将 DSL 扩展为此代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.