使用 table 名称获取模型名称的惯用方法

Idiomatic way to get model name by using table name

阅读 Ecto.schema.metadata 时,我发现我们可以使用模型名称来获取该模型的 table,如下所示:

[
  Ecto.Schema.Metadata,
  nil,
  {nil, table_name},
  :built
] = Map.values(model_name.__struct__.__meta__)

我的问题是我们可以使用 table 名称来获取 table 的型号吗?

据我所知,没有明确的方法可以实现这一点,但由于我们在 Elixir 中,所以一切皆有可能:

with {:ok, mods} <- :application.get_key(:my_app, :modules) do
  mods
  |> Enum.filter(fn mod ->
    try do
      apply(mod, :__schema__, [:source]) == "users"
    rescue
      e in UndefinedFunctionError -> false
    end
  end)
  |> hd()
end
#⇒ MyApp.User # OR `nil`

或者,更精确的检查:

with {:ok, mods} <- :application.get_key(:my_app, :modules) do
  mods
  |> Enum.filter(fn mod ->
    if apply(mod, :__info__, [:functions])[:__schemas__],
      do: apply(mod, :__schema__, [:source]) == "users"
  end)
  |> hd()
end
#⇒ MyApp.User # OR `nil`

我们可以获取应用程序的所有模块,并找到具有 __schema__/1 函数定义的模块,当使用 :source 调用时,returns 名称为 table:

table = "posts"

Application.spec(:my_app, :modules)
|> Enum.find(fn module ->
  function_exported?(module, :__schema__, 1) &&
    module.__schema__(:source) == table
end)
|> IO.inspect

输出:

MyApp.Post