0

也许这不是要走的路,但这是我最初的猜测,我愿意接受提示和更正。

一直在为我部分继承和扩展的简化查询方言编写解析器,允许用户编写如下内容:

plant where accession.code='2018.0047'

它还没有准备好,但是缺少的中间步骤很清楚,除了最后一个:我如何执行结果?

我的目标是等效Ecto.Query.from查询的报价表示。对于上面的例子,就我而言,等效的是:

from(p in "plant", 
  select: [:id], 
  join: a in "accession", 
  on: a.id==p.accession_id, 
  where: a.code=="2018.0047")

我一直在研究__schema__函数返回的结构,一切看起来都很可行,我的意思是我知道如何从模块中提取表名,以及从给定名称的关联中提取所有者和相关模块和键,所以让我们假设我的解析器确实返回了这个值:

{:from, [context: Elixir, import: Ecto.Query],
 [
   {:in, [context: Elixir, import: Kernel], [{:p, [], Elixir}, "plant"]},
   [
     select: [:id],
     join: {:in, [context: Elixir, import: Kernel],
      [{:a, [], Elixir}, "accession"]},
     on: {:==, [context: Elixir, import: Kernel],
      [
        {{:., [], [{:a, [], Elixir}, :id]}, [], []},
        {{:., [], [{:p, [], Elixir}, :accession_id]}, [], []}
      ]},
     where: {:==, [context: Elixir, import: Kernel],
      [{{:., [], [{:a, [], Elixir}, :code]}, [], []}, "2018.0047"]}
   ]
 ]}

如何让 Ecto 执行它?

或者从 yecc 解析器生成 Elixir 代码的最佳方法是什么?

4

1 回答 1

0

简短的回答:,我们不能让 Elixir 执行“引用”的代码。

如果我正确理解了 elixir 论坛上收到的评论,那么该quoted格式仅适用于宏,即用于在编译时定义的内容。

回到例子:

from(p in "plant", 
  select: [:id], 
  join: a in "accession", 
  on: a.id==p.accession_id, 
  where: a.code=="2018.0047")

这样做的结果是一个值,一个Ecto.Query结构,虽然不能立即查看哪些是正在定义的字段,但查看源代码后,我发现我可以逐步生成相同的值,如下所示:

q = %Ecto.Query{}
q = %{ q | from: %Ecto.Query.FromExpr{source: {"plant", nil}}}
q = %{ q | select: %Ecto.Query.SelectExpr{
  expr: [{{:., [], [{:&, [], [0]}, :id]}, [], []}]}}
q = %{ q | joins: [
  %Ecto.Query.JoinExpr{
    source: {"accession", nil}, 
    qual: :inner,
    on: %Ecto.Query.QueryExpr{
      expr: {:==, [], [
        {{:., [], [{:&, [], [0]}, :accession_id]}, [], []},
        {{:., [], [{:&, [], [1]}, :id]}, [], []}
      ]}}}]}
q = %{ q | wheres: [
  %Ecto.Query.BooleanExpr{
    op: :and, 
    expr: {:==, [], [{{:., [], [{:&, [], [1]}, :code]}, [], []}, "2018.0047"]}}]}

我知道它看起来并不容易,但我可以在我的语法作品中使用它。

于 2019-07-06T12:48:31.497 回答