问题描述
假设我有一个要根据其字段之一排序的jsonb字段,它也应该使用dynamic,因为在编译时无法告诉字段名称。我目前拥有的是:
def order_by_dynamic([sort_direction,%{binding_name: binding_name,json_field: json_key,field: field}]) do
[{sort_direction |> String.to_atom(),dynamic([{^binding_name,c}],create_fragment([{c.details,^field},json_key]))}]
end
defmacro create_fragment(fields) do
require Ecto.Query
query = "?->>?"
quote do
fragment(unquote(query),unquote_splicing(fields))
end
end
此代码的问题是它将无法编译:
** (Ecto.Query.CompileError) Tuples can only be used in comparisons with literal tuples of the same size
expanding macro: Ecto.Query.dynamic/2
我还试图在将json字段名称传递给字符串之前将其插入到字符串中,并且错误是:
** (Ecto.Query.CompileError) to prevent sql injection attacks,fragment(...) does not allow strings to be interpolated as the first argument via the `^` operator,got: `"?->>#{json_key}"`
expanding macro: Ecto.Query.dynamic/2
我丢失了某些东西吗,或者使用当前的片段宏无法实现?
解决方法
好吧,看来我了解了,您需要直接从绑定中提供第一个参数,以避免sql注入:
defmacro create_dynamic_fragment(binding_name,field,json_field) do
require Ecto.Query
quote do
dynamic([{^unquote(binding_name),c}],fragment("?->>?",field(c,^unquote(field)),^unquote(json_field)))
end
end