Ecto:如何在更新中调用函数

时间:2017-06-25 06:45:52

标签: elixir ecto

我正在尝试创建一个迁移,通过在该列中的每个项目上调用函数date_str_to_timestamp(在同一文件中定义),将列中的数据转换为不同的格式。

from(p in "posts",
     update: [set: [ timestamp: ^date_str_to_timestamp(p.time) ]])
|> Pesterbot.Repo.update_all([])

但是我得到了这个:

 _build/dev/lib/pesterbot/priv/repo/migrations/20170414014413_posts_to_messages.exs:34

** (Ecto.Query.CompileError) `^(p.time(), date_str_to_timestamp)` is not a valid query expression.

* If you intended to call a database function, please check the documentation
  for Ecto.Query to see the supported database expressions

* If you intended to call an Elixir function or introduce a value,
  you need to explicitly interpolate it with ^

    (ecto) expanding macro: Ecto.Query.update/3
    _build/dev/lib/pesterbot/priv/repo/migrations/20170414014413_posts_to_messages.exs:33: Pesterbot.Repo.Migrations.PostsToMessages.up/0
    (ecto) expanding macro: Ecto.Query.from/2
    _build/dev/lib/pesterbot/priv/repo/migrations/20170414014413_posts_to_messages.exs:33: Pesterbot.Repo.Migrations.PostsToMessages.up/0
    (elixir) expanding macro: Kernel.|>/2
    _build/dev/lib/pesterbot/priv/repo/migrations/20170414014413_posts_to_messages.exs:35: Pesterbot.Repo.Migrations.PostsToMessages.up/0

编辑:@Dogbert

要求的date_str_to_timestamp来源
def date_str_to_timestamp(date_str) do
    {:ok, datetime} = Timex.parse(date_str, "{UNIX}")
    datetime |> Elixir.DateTime.to_unix(:millisecond)
  end
end

编辑: timestamp将是相应time值的纪元以来的整数毫秒,现在是UNIX格式的字符串,例如:Mon Mar 20 19:49:43 CDT 2017

因此Mon Mar 20 19:49:43 CDT 2017应该成为1490057383000

1 个答案:

答案 0 :(得分:1)

您无法在UPDATE查询中调用Elixir函数,因为数据库必须能够评估表达式本身。幸运的是,PostgreSQL确实具有执行Elixir函数功能的功能:

iex(1)> A.date_str_to_timestamp "Tue Mar 5 23:25:19 PST 2013"
1362554719000
postgres=# select EXTRACT(EPOCH FROM 'Tue Mar 5 23:25:19 PST 2013'::timestamp) * 1000;
   ?column?
---------------
 1362525919000
(1 row)

您可以在UPDATE查询中使用此功能:

from(p in "posts",
     update: [set: [timestamp: fragment("EXTRACT(EPOCH FROM ?::timestamp) * 1000", p.time)]])