如何用Absinthe获取指定日期后创建的用户?解决NaiveDateTime类型错误
在Phoenix & Absinthe中实现指定日期后的用户筛选解决方案
嘿,我明白你遇到的问题了——你以为NaiveDateTime能直接解析纯日期字符串,但Absinthe默认的标量规则其实要求带时间的ISO格式。下面给你两种靠谱的解决办法:
方法1:直接用标准NaiveDateTime格式查询
这是最快的解决方式,不用改代码,只需要调整你的GraphQL变量,给日期加上时间部分就行:
你的查询语句不变:
query($filter: UserFilter){ allUsers(filter: $filter){ id firstName lastName } }
把变量改成带时间的格式:
{ "filter": { "insertedAfter": "2018-05-13T00:00:00" } }
这样Absinthe就能自动把这个字符串转成Elixir的NaiveDateTime类型,你的resolver和过滤逻辑完全不用动,直接就能用。
方法2:自定义日期标量(支持纯日期输入)
如果你希望API更友好,能接受"2018-05-13"这种纯日期字符串,那可以自定义一个标量来处理转换:
第一步:在types.ex里添加自定义标量
use Absinthe.Schema.Notation use Absinthe.Ecto, repo: ElixirBlog.Repo import_types Absinthe.Type.Custom # 自定义支持纯日期的标量,自动转成当天0点的NaiveDateTime scalar :date do parse fn input -> with %Absinthe.Blueprint.Input.String{value: date_str} <- input, {:ok, date} <- Date.from_iso8601(date_str), {:ok, naive_dt} <- NaiveDateTime.new(date, ~T[00:00:00]) do {:ok, naive_dt} else _ -> :error end end serialize fn naive_dt -> naive_dt |> NaiveDateTime.to_date() |> Date.to_iso8601() end end # ... 原来的:user类型定义保持不变
第二步:修改UserFilter的字段类型
在schema.ex里,把筛选字段的类型从:naive_datetime换成我们自定义的:date:
input_object :user_filter do field :id, :integer field :first_name, :string field :last_name, :string field :email, :string field :inserted_before, :date # 替换成自定义标量 field :inserted_after, :date # 替换成自定义标量 end
第三步:Resolver逻辑不用改
你的filter_with函数里的日期比较逻辑完全没问题,因为自定义标量已经把纯日期字符串转成了NaiveDateTime(当天的00:00:00),可以直接和数据库的inserted_at字段对比。
进阶:支持多种格式的灵活标量
如果想同时支持纯日期和带时间的格式,可以把自定义标量的解析逻辑写得更灵活:
scalar :flexible_datetime do parse fn input -> with %Absinthe.Blueprint.Input.String{value: str} <- input do # 先尝试解析成完整的NaiveDateTime case NaiveDateTime.from_iso8601(str) do {:ok, ndt} -> {:ok, ndt} _ -> # 失败就尝试解析成Date,再转成当天0点 case Date.from_iso8601(str) do {:ok, date} -> NaiveDateTime.new(date, ~T[00:00:00]) _ -> :error end end end end serialize fn ndt -> NaiveDateTime.to_iso8601(ndt) end end
然后把UserFilter里的字段类型改成:flexible_datetime就可以同时接受两种格式的输入了。
内容的提问来源于stack exchange,提问作者Yuki Umetsu
相关产品推荐
相关产品推荐

