【问题标题】:Building macro for generating fragment that accesses json key构建用于生成访问 json 键的片段的宏
【发布时间】:2021-01-04 23:52:08
【问题描述】:

假设我有一个 jsonb 字段,我想根据其中一个字段对其进行排序,它也应该使用动态,因为在编译时无法告诉字段名称。我目前拥有的是:

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

我是否遗漏了什么,或者当前的片段宏无法实现?

【问题讨论】:

标签: macros elixir ecto


【解决方案1】:

好的,看来我明白了,您需要直接从绑定中提供第一个参数以避免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

【讨论】:

    猜你喜欢
    • 2016-03-31
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-03
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    相关资源
    最近更新 更多