【问题标题】:Om Next's query->ast and ast->query functionsOm Next 的 query->ast 和 ast->query 函数
【发布时间】:2016-06-11 02:06:54
【问题描述】:

根据Om Next's documentation

查询->ast

(om.next/query->ast '[(:foo {:bar 1})])

给定一个查询表达式,返回 AST。

ast->查询

(om.next/ast->query ast)

给定一个查询表达式 AST,将其解析为查询表达式。

问题:为什么需要这些功能?也就是说,为什么需要在 om next 中直接操作查询抽象语法树(我假设它是代表查询树的 clojure 映射以及一些元数据)?

【问题讨论】:

    标签: clojure clojurescript om


    【解决方案1】:

    在某些情况下,您需要直接操作查询 ast。在远程解析模式下,解析器希望您的读取函数返回 {:remote-name true } 或(可能已修改){:remote-name AST-node}(在 env 中以 :ast 形式出现)。大多数情况下,您必须修改 AST 以对其进行重组或添加一些数据。

    示例 1: 您有疑问:[{:widget {:list [:name :created]}}] :widget 部分是纯 UI 相关的,您的服务器不需要知道它的存在,它只关心/知道 :list。 基本上你必须在解析器中修改 AST:

    (defmethod read :list
      [{:keys [ast query state]} key _ ]
      (let [st @state]
        {:value (om/db->tree query (get st key) st)
         :remote (assoc ast :query-root true)}))
    

    如果您在发送函数中使用om/process-roots,它将从ast 中提取:query-root,并将查询从[{:widget {:list [:name :created]}}] 重写为[{:list [:name :created]}]

    示例 2: 另一个例子是当你想在远程改变一些东西时:

    (defmethod mutate 'item/update
      [{:keys [state ast]} key {:keys [id title]}]
      {:remote (assoc ast :params {:data {:id id :title title })})
    

    在这里,您需要明确告诉 Om 将您要发送的数据包含在 AST 中。然后在您的遥控器上选择 :data 以更新给定 id 的标题

    大多数情况下,您不会直接使用您在问题中描述的功能。解析器的每个方法中可用的env 中都有ast

    【讨论】:

    • 请注意:您从未使用过 George 要求的任何功能 :)
    • @Andre:这个答案仍然非常有用!此外,他说大多数时候这些功能在实践中不会被太多使用。
    • 阅读器函数中的:remote 键是否总是必须将查询 ast 作为其值?或者它可以仅仅返回一个原始查询(即,使用 Datomic pull 语法的表单[ ... ])?
    • 它可以是 ast 或只是一个布尔值 true 来标记某个遥控器。对于ast,它必须是ast,而不是查询。但是,如果您想在发送 ast 之前直接修改查询而不是 ast,则可以使用 (om/query->ast)。请记住,最终结果必须是有效的 ast。一旦掌握了窍门,从 env 修改 ast 就像喝水或呼吸空气一样;)
    【解决方案2】:

    我在尝试使用 Compassus 时偶然发现的东西:

    假设您有一个包含参数子查询的复杂联合/连接查询。像这样的:

    `[({:foo/info
            {:foo/header [:foo-id :name]
            :foo/details [:id :description :title]}} {:foo-id ~'?foo-id
                                                      :foo-desc ~'?foo-desc})]
    

    现在假设您想在服务器上设置参数,您可以使用 om/parser 解析它,并将这些参数视为read dispatch 的第三个参数。当然,可以编写一个函数,在查询中找到所有必要的参数并设置值。但这并不容易,正如我所说 - 想象一下您的查询可能非常复杂。

    所以你可以做的是修改ast,ast包含:children :params键。所以假设:foo-id:foo-desc 的实际值在:route-params 键下的状态原子中:

    (defn set-ast-params [children params]
      "traverses given vector of `children' in an AST and sets `params`"
      (mapv
        (fn [c]
          (let [ks (clojure.set/intersection (-> params keys set) 
                                             (-> c :params keys set))]
            (update-in c [:params] #(merge % (select-keys params (vec ks))))))
        children))
    
    (defmethod readf :foo/info
      [{:keys [state query ast] :as env} k params]
      (let [{:keys [route-params] :as st} @state
            ast' (-> ast 
                     (update :children #(set-ast-params % route-params))
                     om/ast->query
                     om.next.impl.parser/expr->ast)]
        {:value  (get st k)
        :remote ast'}))
    

    所以基本上你是: - 抓住 ast - 用实际值修改它 您认为也许您可以立即将其发送到服务器。唉,不!还没有。事情是 - 当您执行 {:remote ast} 时,Om 会获取 :query 部分的 ast,从中组合 ast,然后将其发送到服务器。因此,您实际上需要:将修改后的 ast 转换为查询,然后再次将其转换回 ast。

    注意事项:

    • 此示例中的set-ast-params 函数仅适用于第一级(如果您有嵌套的参数化查询 - 它不起作用), 让它递归 - 这并不难

    • 将 ast 转换为 query 有两种不同的方式,反之亦然:

      (om/ast->query) ;; retrieves query from ast and sets the params based 
                      ;; of `:params` key of the ast, BUT. it modifies the query, 
                      ;; if you have a join query it takes only the first item in it. e.g. :
      [({:foo/foo [:id]
          :bar/bar [:id]} {:id ~'?id})]
      ;; will lose its `:bar` part 
      
      (om.next.impl.parser/ast->expr) ;; retrieves query from an ast, 
                                      ;; but doesn't set query params based on `:params` keys of the ast.
      
      ;; there are also
      (om/query->ast) ;; and
      (om.next.impl.parser/expr->ast)
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-11-19
      • 2021-02-19
      • 2014-10-13
      • 2022-12-08
      • 1970-01-01
      • 1970-01-01
      • 2022-07-01
      相关资源
      最近更新 更多