我正在使用Phoenix和Ecto 2.0构建一个应用程序,它在多个模型中存储了大量数据。
我想允许用户执行查询并仅选择所有字段的子集。
我已经能够使标准完美运行(在这方面,Ecto比我预期的更容易使用;对开发者来说是很大的道具!),但是我还没有弄清楚选择的东西。 / p>
我的初始查询如下所示:
query =
from e in Event,
left_join: t in assoc(e, :event_type),
left_join: r in assoc(e, :event_reason_code),
left_join: o in assoc(e, :event_outcome_code),
left_join: i in assoc(e, :item),
left_join: l in assoc(e, :location),
left_join: c in assoc(l, :client)
我希望能够动态分配一个选择。
现在,我看起来像:
["event.id", "client.name", ...]
然后根据第一个句点之前的内容进行模式匹配,然后构建SQL以选择正确的字段。
我尝试过这样的事情让你知道我想要完成的事情:
defp build_selects(query, event_query) do
select query, [e, t, r, o, i, l, c], Enum.reduce(event_query.select, {}, fn(key, acc) ->
field =
case key do
"event.info." <> rest -> fragment("?->>?", field(e, :info), String.to_atom(rest))
"event." <> rest -> field(e, String.to_atom(rest))
"event_type." <> rest -> field(t, String.to_atom(rest))
"event_reason_code." <> rest -> field(r, String.to_atom(rest))
"event_outcome_code." <> rest -> field(o, String.to_atom(rest))
"item.info." <> rest -> fragment("?->>?", field(i, :info), String.to_atom(rest))
"item." <> rest -> field(i, String.to_atom(rest))
"location.info." <> rest -> fragment("?->>?", field(l, :info), String.to_atom(rest))
"location." <> rest -> field(l, String.to_atom(rest))
"client.info." <> rest -> fragment("?->>?", field(c, :info), String.to_atom(rest))
"client." <> rest -> field(c, String.to_atom(rest))
end
Tuple.append acc, field
end)
end
不幸的是,在undefined function c/0
内的build_select/2
电话中,此操作失败并显示错误build_selects/2
。
我已经找到了一种使用原始SQL构建查询的方法,该方法运行良好,但我知道这可以让自己打开注射攻击之类的东西,所以我想站在Ecto的肩膀上,如果可能的话
我希望这是有道理的;如果不是,我会试着澄清。
谢谢!
我浏览了更多Ecto的源代码并遇到了Ecto.Query.API.take
,这似乎符合要求。我尝试创建一个包含所有模型和要选择的字段列表(如果有)的地图(称为s_map
)。然后我在这里设置选择:
from [e, t, r, o, i, l, c] in query,
select: {take(e, ^Map.get(s_map, :event, [])),
take(t, ^Map.get(s_map, :event_type, [])),
take(r, ^Map.get(s_map, :event_reason_code, [])),
take(o, ^Map.get(s_map, :event_outcome_code, [])),
take(i, ^Map.get(s_map, :item, [])),
take(l, ^Map.get(s_map, :location, [])),
take(c, ^Map.get(s_map, :client, []))}
这似乎也没有完全奏效,因为必须至少有一个字段或其他错误。
答案 0 :(得分:0)
对于“至少一个字段或其它错误”的问题,我将构建一个指定函数中的select的元组。该函数将检查以确保选择某个列。如果调用者没有指定有效列,则应返回错误。然后,您可以决定如何在调用者中处理该错误。