Om Next read multi-fn 未在二级连接中调用,查询 AST 未完全解析,因此组件仅接收标识

Om Next read multi-fn not being called in second level join, Query AST not parsed fully, therefore component only receiving idents

我无法让二级连接正常工作。为了简洁起见,我在这里省略了一些内容。

我的根组件是:

(defui RootView
  static om/IQuery
  (query [this]
    `[{:list/events ~(om/get-query Event)}])
  Object
  (render [this]
    (let [{:keys [list/events]} (om/props this)]
      (events/event-list events))))

我的查询组合正确,初始数据正确规范化。我不会显示规范化数据,总查询还有更多内容。

(prn (om/get-query RootView)) =>

[{:list/events
  [:id
   {:body [:id :text :headline]}
   {:media [:id :url :caption :credit]}
   {:start-date [:id :year :month :day]}]}]

如果我 运行 包含通过解析器连接的查询,我得到:

(prn (parser {:state (atom norm-data)}
       '[{:list/events
          [:id
           {:body [:id :text :headline]}
           {:media [:id :url :caption :credit]}
           {:start-date [:id :year :month :day]}]}])) =>

{:list/events
 [{:id 1,
   :media [:media/by-id 1],
   :start-date [:start-date/by-id 1],
   :body [:body/by-id 1]}
  {:id 17,
   :media [:media/by-id 17],
   :start-date [:start-date/by-id 17],
   :body [:body/by-id 17]}]}

因此调用了 :list/events 的读取函数并且 returns 它是数据,尽管 :body、:media 和 :start-date 的所有第二个连接都不是。

我的读取函数如下,第二个是没有调用的。我省略了 :media 和 :start-date 上的多种方法,它们也没有被调用。我不确定这是什么症状。

(defmulti read om/dispatch)

(defmethod read :list/events
  [{:keys [state] :as env} key params]
  (let [st @state]
    {:value (into [] (map #(get-in st %)) (get st key))}))

(defmethod read :body
  [{:keys [state query]} key _]
  (println "This is never printed")
  {:value :doesnt-matter})

连接在 AST 中被正确识别(所以我假设查询语法是正确的)并且调度键与多方法的匹配。

(prn (om/query->ast (om/get-query RootView))) =>

{:type :root,
 :children
 [{:type :join,
   :dispatch-key :list/events,
   :key :list/events,
   :query
   [:id
    {:body [:id :text :headline]}
    {:media [:id :url :caption :credit]}
    {:start-date [:id :year :month :day]}],
   :component timeline.components.events/Event,
   :children
   [{:type :prop, :dispatch-key :id, :key :id}
    {:type :join,
     :dispatch-key :body,
     :key :body,
     :query [:id :text :headline],
     :component timeline.components.events/EventBody,
     :children
     [{:type :prop, :dispatch-key :id, :key :id}
      {:type :prop, :dispatch-key :text, :key :text}
      {:type :prop, :dispatch-key :headline, :key :headline}]}]}]}

我不明白为什么解析器或其他东西(?)在第二次连接时停止?就我有限的理解而言,至少应该调用 :body 上的 multi-method?

所以我遇到的问题是我认为的理解之一,Om Slack 频道中的 António Monteiro 建议我使用 db->tree 函数。在 :list/events 多方法中使用它让我们 return 整个去规范化数据树。

您必须自己从读取内部进行递归,即在被检查的键内的查询上调用解析器。 db->tree 为您做这件事。事实上,每个 read 调用 db->tree 并因此看起来几乎相同的情况并不少见。事实上,正因为如此,Untangled 完全取消了这些阅读。在这种情况下,您真的不必自己进行递归!

这里没有递归:

(into [] (map #(get-in st %)) (get st key)) 

key 上的任何 getrefs 部分 default db 格式化 数据(应用程序数据)。因此,(get st key) 将返回一系列标识。任何 get-in 都是应用程序数据的表部分,因此 returns 真实数据值。 (map #(get-in st %)) 是为每个身份执行此操作的转换器。但是数据的 表部分 是一个递归数据结构 - 必须是因为没有重复 - 所以任何不是 'leaf' 数据的数据都由一个标识表示。所以这就是您要返回的内容 - 任何深一层的东西,否则就是标识。

如果不了解默认数据库格式 - refstables 部分,这个答案几乎毫无意义。到目前为止我找到的最好的解释是 here

此数据 (st) 采用 默认数据库格式:

{ :list/people [[:people/by-id 1] [:people/by-id 2] ... ]
  :people/by-id { 1 { :db/id 1 :person/name "Joe" :person/mate [:people/by-id 2]}
                  2 { :db/id 2 :person/name "Sally" :person/mate [:people/by-id 1]}}}

无论您在哪里看到 by-id,都表明密钥在 tables mapentry 中。正如您在结构中看到的那样,(get-in st [:people/by-id 1]) 将为您检索一张地图,该地图是真实数据,当然只有一层深度。

这里 :list/people 是一个键,其中关联的值是一个标识向量。 (get st :list/people) 会给你这个向量。此映射是 st.

refs 部分