я могу заставить Elixir выполнять цитируемый код, соответствующий переменной? - PullRequest
0 голосов
/ 03 июля 2019

возможно, это не тот путь, но это было мое первоначальное предположение, и я открыт для подсказок и исправлений.

Я писал парсер для сокращенного диалекта запросов, который я частично унаследовал и значительно расширил, что позволяет пользователям писать такие вещи как:

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__, и все выглядит вполне выполнимо. Я имею в виду, что знаю, как извлечь имя таблицы из модулей, а также владельца и связанные модули и ключи из ассоциации, учитывая ее name, поэтому давайте предположим, что мой синтаксический анализатор возвращает это значение:

{: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"]}
   ]
 ]}

как заставить Экто выполнить это?

или каков наилучший способ получения кода Elixir из анализатора yecc?

1 Ответ

0 голосов
/ 06 июля 2019

короткий ответ: нет , мы не можем заставить 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"]}}]}

Я знаю, что это не выглядит легче, но я могу использовать это в моих грамматических постановках.

...