浏览代码

enhance(perf): delay query for linked references

Tienson Qin 4 年之前
父节点
当前提交
295a07a1a7
共有 3 个文件被更改,包括 134 次插入70 次删除
  1. 73 68
      src/main/frontend/components/reference.cljs
  2. 58 0
      src/main/frontend/db/model.cljs
  3. 3 2
      src/main/frontend/ui.cljs

+ 73 - 68
src/main/frontend/components/reference.cljs

@@ -6,6 +6,7 @@
             [frontend.components.svg :as svg]
             [frontend.date :as date]
             [frontend.db :as db]
+            [frontend.db.model :as model-db]
             [frontend.db-mixins :as db-mixins]
             [frontend.handler.block :as block-handler]
             [frontend.handler.page :as page-handler]
@@ -67,6 +68,7 @@
     page-blocks))
 
 (rum/defcs references < rum/reactive db-mixins/query
+  (rum/local nil ::n-ref)
   {:init (fn [state]
            (let [page-name (first (:rum/args state))
                  filters (when page-name
@@ -74,78 +76,81 @@
              (assoc state ::filters filters)))}
   [state page-name marker? priority?]
   (when page-name
-    (let [filters-atom (get state ::filters)
+    (let [repo (state/get-current-repo)
+          threshold (state/get-linked-references-collapsed-threshold)
+          refed-blocks-ids (model-db/get-referenced-blocks-ids page-name)
+          *n-ref (::n-ref state)
+          n-ref (or (rum/react *n-ref) (count refed-blocks-ids))
+          default-collapsed? (>= (count refed-blocks-ids) threshold)
+          filters-atom (get state ::filters)
+          filter-state (rum/react filters-atom)
           block? (util/uuid-string? page-name)
           block-id (and block? (uuid page-name))
           page-name (string/lower-case page-name)
           journal? (date/valid-journal-title? (string/capitalize page-name))
-          repo (state/get-current-repo)
-          ref-blocks (cond
-                       block-id
-                       (db/get-block-referenced-blocks block-id)
-                       :else
-                       (db/get-page-referenced-blocks page-name))
-          ref-pages (map (comp :block/original-name first) ref-blocks)
-          references (db/get-page-linked-refs-refed-pages repo page-name)
-          references (->> (concat ref-pages references)
-                          (remove nil?)
-                          (distinct))
-          scheduled-or-deadlines (if (and journal?
-                                          (not (true? (state/scheduled-deadlines-disabled?)))
-                                          (= page-name (string/lower-case (date/journal-name))))
-                                   (db/get-date-scheduled-or-deadlines (string/capitalize page-name))
-                                   nil)
-          threshold (state/get-linked-references-collapsed-threshold)]
-      (let [filter-state (rum/react filters-atom)
-            filters (when (seq filter-state)
-                      (->> (group-by second filter-state)
-                           (medley/map-vals #(map first %))))
-            filtered-ref-blocks (->> (block-handler/filter-blocks repo ref-blocks filters true)
-                                     blocks-with-ref-level)
-            n-ref (apply +
-                    (for [[_ rfs] filtered-ref-blocks]
-                      (count rfs)))]
-        (when (or (> n-ref 0)
-                  (seq scheduled-or-deadlines)
-                  (seq filter-state))
-          [:div.references.mt-6.flex-1.flex-row
-           [:div.content
-            (when (seq scheduled-or-deadlines)
-              (ui/foldable
-               [:h2.font-bold.opacity-50 "SCHEDULED AND DEADLINE"]
-               [:div.references-blocks.mb-6
-                (let [ref-hiccup (block/->hiccup scheduled-or-deadlines
-                                                 {:id (str page-name "-agenda")
-                                                  :ref? true
-                                                  :group-by-page? true
-                                                  :editor-box editor/box}
-                                                 {})]
-                  (content/content page-name
-                                   {:hiccup ref-hiccup}))]
-               {}))
+          scheduled-or-deadlines (when (and journal?
+                                            (not (true? (state/scheduled-deadlines-disabled?)))
+                                            (= page-name (string/lower-case (date/journal-name))))
+                                   (db/get-date-scheduled-or-deadlines (string/capitalize page-name)))]
+      (when (or (seq refed-blocks-ids)
+                (seq scheduled-or-deadlines)
+                (seq filter-state))
+        [:div.references.mt-6.flex-1.flex-row
+         [:div.content
+          (when (seq scheduled-or-deadlines)
+            (ui/foldable
+             [:h2.font-bold.opacity-50 "SCHEDULED AND DEADLINE"]
+             [:div.references-blocks.mb-6
+              (let [ref-hiccup (block/->hiccup scheduled-or-deadlines
+                                               {:id (str page-name "-agenda")
+                                                :ref? true
+                                                :group-by-page? true
+                                                :editor-box editor/box}
+                                               {})]
+                (content/content page-name {:hiccup ref-hiccup}))]
+             {}))
 
-            (when (or (> n-ref 0)
-                      (seq filter-state))
-              (ui/foldable
-               [:div.flex.flex-row.flex-1.justify-between.items-center
-                [:h2.font-bold.opacity-50 (let []
-                                            (str n-ref " Linked Reference"
-                                                 (when (> n-ref 1) "s")))]
-                [:a.filter.fade-link
-                 {:title "Filter"
-                  :on-click #(state/set-modal! (filter-dialog filters-atom references page-name))}
-                 (ui/icon "filter" {:class (cond
-                                             (empty? filter-state)
-                                             ""
-                                             (every? true? (vals filter-state))
-                                             "text-green-400"
-                                             (every? false? (vals filter-state))
-                                             "text-red-400"
-                                             :else
-                                             "text-yellow-400")
-                                    :style {:fontSize 24}})]]
+          (when (seq refed-blocks-ids)
+            (ui/foldable
+             [:div.flex.flex-row.flex-1.justify-between.items-center
+              [:h2.font-bold.opacity-50 (str n-ref " Linked Reference"
+                                             (when (> n-ref 1) "s"))]
+              [:a.filter.fade-link
+               {:title "Filter"
+                :on-click (fn []
+                            (let [ref-blocks (if block-id
+                                               (db/get-block-referenced-blocks block-id)
+                                               (db/get-page-referenced-blocks page-name))
+                                  ref-pages (map (comp :block/original-name first) ref-blocks)
+                                  references (db/get-page-linked-refs-refed-pages repo page-name)
+                                  references (->> (concat ref-pages references)
+                                                  (remove nil?)
+                                                  (distinct))]
+                              (state/set-modal! (filter-dialog filters-atom references page-name))))}
+               (ui/icon "filter" {:class (cond
+                                           (empty? filter-state)
+                                           ""
+                                           (every? true? (vals filter-state))
+                                           "text-green-400"
+                                           (every? false? (vals filter-state))
+                                           "text-red-400"
+                                           :else
+                                           "text-yellow-400")
+                                  :style {:fontSize 24}})]]
 
-               (fn []
+             (fn []
+               (let [ref-blocks (if block-id
+                                  (db/get-block-referenced-blocks block-id)
+                                  (db/get-page-referenced-blocks page-name))
+                     filters (when (seq filter-state)
+                               (->> (group-by second filter-state)
+                                    (medley/map-vals #(map first %))))
+                     filtered-ref-blocks (->> (block-handler/filter-blocks repo ref-blocks filters true)
+                                              blocks-with-ref-level)
+                     n-ref (apply +
+                             (for [[_ rfs] filtered-ref-blocks]
+                               (count rfs)))]
+                 (reset! *n-ref n-ref)
                  [:div.references-blocks
                   (let [ref-hiccup (block/->hiccup filtered-ref-blocks
                                                    {:id page-name
@@ -156,9 +161,9 @@
                                                     :filters filters}
                                                    {})]
                     (content/content page-name
-                                     {:hiccup ref-hiccup}))])
+                                     {:hiccup ref-hiccup}))]))
 
-               {:default-collapsed? (>= n-ref threshold)}))]])))))
+             {:default-collapsed? default-collapsed?}))]]))))
 
 (rum/defcs unlinked-references-aux
   < rum/reactive db-mixins/query

+ 58 - 0
src/main/frontend/db/model.cljs

@@ -962,6 +962,43 @@
                                   [k blocks]))))]
          result)))))
 
+(defn get-page-referenced-blocks-ids
+  "Faster and can be used for pagination later."
+  ([page]
+   (get-page-referenced-blocks-ids (state/get-current-repo) page))
+  ([repo page]
+   (when repo
+     (when-let [conn (conn/get-conn repo)]
+       (let [page-id (:db/id (db-utils/entity [:block/name page]))
+             pages (page-alias-set repo page)
+             aliases (set/difference pages #{page-id})
+             query-result (if (seq aliases)
+                            (let [rules '[[(find-blocks ?block ?ref-page ?pages ?alias ?aliases)
+                                           [?block :block/page ?alias]
+                                           [(contains? ?aliases ?alias)]]
+                                          [(find-blocks ?block ?ref-page ?pages ?alias ?aliases)
+                                           [?block :block/refs ?ref-page]
+                                           [(contains? ?pages ?ref-page)]]]]
+                              (d/q
+                                '[:find ?block
+                                  :in $ % ?pages ?aliases ?block-attrs
+                                  :where
+                                  (find-blocks ?block ?ref-page ?pages ?alias ?aliases)]
+                                conn
+                                rules
+                                pages
+                                aliases
+                                block-attrs))
+                            (d/q
+                              '[:find ?ref-block
+                                :in $ ?page ?block-attrs
+                                :where
+                                [?ref-block :block/refs ?page]]
+                              conn
+                              page-id
+                              block-attrs))]
+         query-result)))))
+
 (defn get-date-scheduled-or-deadlines
   [journal-title]
   (when-let [date (date/journal-title->int journal-title)]
@@ -1039,6 +1076,27 @@
             (sort-by-left-recursive)
             db-utils/group-by-page)))))
 
+(defn get-block-referenced-blocks-ids
+  [block-uuid]
+  (when-let [repo (state/get-current-repo)]
+    (when-let [conn (conn/get-conn repo)]
+      (let [block (db-utils/entity [:block/uuid block-uuid])]
+        (->> (react/q repo [:ref-ids (:db/id block)] {}
+               '[:find ?ref-block
+                 :in $ ?block-uuid ?block-attrs
+                 :where
+                 [?block :block/uuid ?block-uuid]
+                 [?ref-block :block/refs ?block]]
+               block-uuid
+               block-attrs)
+             react)))))
+
+(defn get-referenced-blocks-ids
+  [page-name-or-block-uuid]
+  (if (uuid? page-name-or-block-uuid)
+    (get-block-referenced-blocks-ids page-name-or-block-uuid)
+    (get-page-referenced-blocks-ids page-name-or-block-uuid)))
+
 (defn get-matched-blocks
   [match-fn limit]
   (when-let [repo (state/get-current-repo)]

+ 3 - 2
src/main/frontend/ui.cljs

@@ -21,7 +21,8 @@
             ["react-transition-group" :refer [CSSTransition TransitionGroup]]
             ["react-tweet-embed" :as react-tweet-embed]
             [rum.core :as rum]
-            [clojure.string :as str]))
+            [clojure.string :as str]
+            [frontend.db-mixins :as db-mixins]))
 
 (defonce transition-group (r/adapt-class TransitionGroup))
 (defonce css-transition (r/adapt-class CSSTransition))
@@ -575,7 +576,7 @@
    {:class (if collapsed? "rotating-arrow collapsed" "rotating-arrow not-collapsed")}
    (svg/caret-right)])
 
-(rum/defcs foldable <
+(rum/defcs foldable < db-mixins/query rum/reactive
   (rum/local false ::control?)
   (rum/local false ::collapsed?)
   {:will-mount (fn [state]