Просмотр исходного кода

enhance(perf): avoid re-run built-in queries when collapsed

Tienson Qin 7 месяцев назад
Родитель
Сommit
33331cc3e6

+ 2 - 1
src/main/frontend/components/page.cljs

@@ -207,7 +207,8 @@
                 (query/custom-query (component-block/wrap-query-components
                                      {:attr {:class "mt-10"}
                                       :editor-box editor/box
-                                      :page page-cp})
+                                      :page page-cp
+                                      :built-in-query? true})
                                     query'))
                (str repo "-custom-query-" (:query query')))))]))))
 

+ 17 - 8
src/main/frontend/components/query.cljs

@@ -8,6 +8,7 @@
             [frontend.context.i18n :refer [t]]
             [frontend.db :as db]
             [frontend.db-mixins :as db-mixins]
+            [frontend.db.react :as react]
             [frontend.extensions.sci :as sci]
             [frontend.handler.editor :as editor-handler]
             [frontend.state :as state]
@@ -129,13 +130,20 @@
 
 (rum/defcs custom-query* < rum/reactive db-mixins/query
   {:init (fn [state]
-           (assoc state ::result (atom nil)))}
+           (let [[config q] (:rum/args state)]
+             (assoc state
+                    ::result (atom nil)
+                    ::collapsed? (atom (or (:collapsed? q) (:collapsed? config))))))}
   [state {:keys [*query-error db-graph? dsl-query? built-in-query? table? current-block] :as config}
-   {:keys [builder query view collapsed?] :as q}]
+   {:keys [builder query view _collapsed?] :as q}]
   (let [*result (::result state)
-        collapsed?' (:collapsed? config)
-        result' (query-result/run-custom-query config q *result *query-error)
-        result (when result' (query-result/transform-query-result config q result'))
+        *collapsed? (::collapsed? state)
+        collapsed? (rum/react *collapsed?)
+        [k result] (query-result/run-custom-query config q *result *query-error)
+        result (some->> result
+                        (query-result/transform-query-result config q))
+        _ (when k
+            (react/set-q-collapsed! k collapsed?))
         ;; Remove hidden pages from result
         result (if (and (coll? result) (not (map? result)))
                  (->> result
@@ -169,7 +177,7 @@
                                             :page-list? page-list?
                                             :*result *result
                                             :result result
-                                            :collapsed? collapsed?'}))
+                                            :collapsed? collapsed?}))
 
          (when (and dsl-query? builder) builder)
 
@@ -180,9 +188,10 @@
              (fn []
                (custom-query-inner config q opts))
              {:default-collapsed? collapsed?
-              :title-trigger? true})]
+              :title-trigger? true
+              :on-pointer-down #(reset! *collapsed? %)})]
            [:div.bd
-            (when-not collapsed?'
+            (when-not collapsed?
               (custom-query-inner config q opts))])]))))
 
 (rum/defcs custom-query < rum/static

+ 26 - 24
src/main/frontend/components/query/result.cljs

@@ -25,35 +25,37 @@
     (try
       (cond
         (:dsl-query? config)
-        (let [q (:query query)
-              form (common-util/safe-read-string {:log-error? false} q)]
-          (cond
-            (and (symbol? form)
+        (let [result (let [q (:query query)
+                           form (common-util/safe-read-string {:log-error? false} q)]
+                       (cond
+                         (and (symbol? form)
                  ;; Queries only containing template should trigger a query
-                 (not (re-matches template/template-re (string/trim q))))
-            nil
+                              (not (re-matches template/template-re (string/trim q))))
+                         nil
 
-            (re-matches #"^\".*\"$" q) ; full-text search
-            (do
-              (p/let [blocks (search/block-search repo (string/trim form) {:limit 30})]
-                (when (seq blocks)
-                  (let [result (->> blocks
-                                    (keep (fn [b]
-                                            (when-not (= (:block/uuid b) current-block-uuid)
-                                              (let [entity (or (db/entity [:block/uuid (:block/uuid b)]) b)]
-                                                (when-not (ldb/hidden? entity)
-                                                  entity))))))]
-                    (reset! *result result))))
-              (rum/react *result))
+                         (re-matches #"^\".*\"$" q) ; full-text search
+                         (do
+                           (p/let [blocks (search/block-search repo (string/trim form) {:limit 30})]
+                             (when (seq blocks)
+                               (let [result (->> blocks
+                                                 (keep (fn [b]
+                                                         (when-not (= (:block/uuid b) current-block-uuid)
+                                                           (let [entity (or (db/entity [:block/uuid (:block/uuid b)]) b)]
+                                                             (when-not (ldb/hidden? entity)
+                                                               entity))))))]
+                                 (reset! *result result))))
+                           (rum/react *result))
 
-            :else
-            (let [result (query-dsl/query (state/get-current-repo) q {:cards? (:cards? config)})]
-              (when (util/atom? result)
-                (rum/react result)))))
+                         :else
+                         (let [result (query-dsl/query (state/get-current-repo) q {:cards? (:cards? config)})]
+                           (when (util/atom? result)
+                             (rum/react result)))))]
+          [nil result])
 
         :else
-        (util/react (query-custom/custom-query query {:current-block-uuid current-block-uuid
-                                                      :built-in-query? (:built-in-query? config)})))
+        (let [[k result] (query-custom/custom-query query {:current-block-uuid current-block-uuid
+                                                           :built-in-query? (:built-in-query? config)})]
+          [k (rum/react result)]))
       (catch :default e
         (reset! *query-error e)))))
 

+ 1 - 1
src/main/frontend/db/query_custom.cljs

@@ -80,7 +80,7 @@
                         (assoc query-opts :query-string (str query)))]
      (if (or (list? (:query query'))
              (not= :find (first (:query query')))) ; dsl query
-       (query-dsl/custom-query repo query' query-opts)
+       [nil (query-dsl/custom-query repo query' query-opts)]
        (query-react/react-query repo
                                 (add-rules-to-query query' {:db-graph? db-graph?})
                                 query-opts)))))

+ 19 - 19
src/main/frontend/db/query_dsl.cljs

@@ -766,13 +766,13 @@ Some bindings in this fn:
                           #(sort-by % (fn [m prop] (get-in m [:block/properties prop])))
                           identity)
                transform-fn (comp sort-by' random-samples)]
-           (query-react/react-query repo
-                                    {:query query'
-                                     :query-string query-string
-                                     :rules rules}
-                                    (merge
-                                     {:transform-fn transform-fn}
-                                     query-opts))))))))
+           (last (query-react/react-query repo
+                                          {:query query'
+                                           :query-string query-string
+                                           :rules rules}
+                                          (merge
+                                           {:transform-fn transform-fn}
+                                           query-opts)))))))))
 
 (defn custom-query
   "Runs a dsl query with query as a seq. Primary use is from advanced query"
@@ -783,18 +783,18 @@ Some bindings in this fn:
           {query* :query :keys [sort-by blocks? rules]} (parse query-string {:db-graph? db-graph?})]
       (when-let [query' (some-> query* (query-wrapper {:blocks? blocks?
                                                        :block-attrs (when db-graph? db-block-attrs)}))]
-        (query-react/react-query repo
-                                 (merge
-                                  query-m
-                                  {:query query'
-                                   :rules rules})
-                                 (merge
-                                  query-opts
-                                  (when sort-by
-                                    {:transform-fn
-                                     (if db-graph?
-                                       identity
-                                       #(sort-by % (fn [m prop] (get-in m [:block/properties prop]))))})))))))
+        (last (query-react/react-query repo
+                                       (merge
+                                        query-m
+                                        {:query query'
+                                         :rules rules})
+                                       (merge
+                                        query-opts
+                                        (when sort-by
+                                          {:transform-fn
+                                           (if db-graph?
+                                             identity
+                                             #(sort-by % (fn [m prop] (get-in m [:block/properties prop]))))}))))))))
 
 (defn query-contains-filter?
   [query' filter-name]

+ 1 - 1
src/main/frontend/db/query_react.cljs

@@ -114,4 +114,4 @@
       (pprint "query-opts:" query-opts)
       (pprint (str "time elapsed: " (.toFixed (- (.now js/performance) start-time) 2) "ms"))
       (when config/dev? (js/console.groupEnd))
-      (apply react/q repo k query-opts query inputs))))
+      [k (apply react/q repo k query-opts query inputs)])))

+ 27 - 13
src/main/frontend/db/react.cljs

@@ -16,7 +16,18 @@
 ;; Query atom of map of Key ([repo q inputs]) -> atom
 ;; TODO: replace with LRUCache, only keep the latest 20 or 50 items?
 
-(defonce query-state (atom {}))
+(defonce *query-state (atom {}))
+
+;; [[repo q]]
+(defonce *collapsed-queries (atom {}))
+
+(defn set-q-collapsed!
+  [k collapsed?]
+  (swap! *collapsed-queries assoc k collapsed?))
+
+(defn- query-collapsed?
+  [k]
+  (@*collapsed-queries k))
 
 ;; Current dynamic component
 (def ^:dynamic *query-component* nil)
@@ -31,26 +42,27 @@
 
 (defn set-new-result!
   [k new-result]
-  (when-let [result-atom (get-in @query-state [k :result])]
+  (when-let [result-atom (get-in @*query-state [k :result])]
     (reset! result-atom new-result)))
 
 (defn clear-query-state!
   []
-  (reset! query-state {}))
+  (reset! *query-state {})
+  (reset! *collapsed-queries {}))
 
 (defn add-q!
   [k query inputs result-atom transform-fn query-fn inputs-fn]
-  (swap! query-state assoc k {:query query
-                              :inputs inputs
-                              :result result-atom
-                              :transform-fn transform-fn
-                              :query-fn query-fn
-                              :inputs-fn inputs-fn})
+  (swap! *query-state assoc k {:query query
+                               :inputs inputs
+                               :result result-atom
+                               :transform-fn transform-fn
+                               :query-fn query-fn
+                               :inputs-fn inputs-fn})
   result-atom)
 
 (defn remove-q!
   [k]
-  (swap! query-state dissoc k))
+  (swap! *query-state dissoc k))
 
 (defn add-query-component!
   [k component]
@@ -75,7 +87,7 @@
 
 (defn get-query-cached-result
   [k]
-  (when-let [result (get @query-state k)]
+  (when-let [result (get @*query-state k)]
     (when (satisfies? IWithMeta @(:result result))
       (set! (.-state (:result result))
             @(:result result)))
@@ -168,7 +180,7 @@
                               (when (and (= (first k) repo-url)
                                          (or (contains? affected-keys-set k')
                                              (contains? #{:custom :kv} (first k'))))
-                                [k' cache]))) @query-state)
+                                [k' cache]))) @*query-state)
                     (into {}))
          all-keys (concat (distinct affected-keys)
                           (when-not skip-kv-custom-keys?
@@ -181,7 +193,9 @@
              (try
                (let [f #(execute-query! repo-url db (vec (cons repo-url k)) cache)]
                  (if custom?
-                   (async/put! (state/get-reactive-custom-queries-chan) [f query])
+                   ;; perf: don't execute custom queries if they were collapsed
+                   (when-not (query-collapsed? k)
+                     (async/put! (state/get-reactive-custom-queries-chan) [f query]))
                    (f)))
                (catch :default e
                  (js/console.error e)

+ 31 - 31
src/main/frontend/extensions/srs.cljs

@@ -267,13 +267,13 @@
                       (when-let [query' (query-dsl/query-wrapper query*
                                                                  {:blocks? true
                                                                   :block-attrs [:db/id :block/properties]})]
-                        (let [result (query-react/react-query repo
-                                                              {:query (with-meta query' {:cards-query? true})
-                                                               :rules (or rules [])}
-                                                              (merge
-                                                               {:use-cache? use-cache?}
-                                                               (when sort-by
-                                                                 {:transform-fn sort-by})))]
+                        (let [result (last (query-react/react-query repo
+                                                                    {:query (with-meta query' {:cards-query? true})
+                                                                     :rules (or rules [])}
+                                                                    (merge
+                                                                     {:use-cache? use-cache?}
+                                                                     (when sort-by
+                                                                       {:transform-fn sort-by}))))]
                           (when result
                             (flatten (util/react result)))))))]
        (vec result)))))
@@ -489,16 +489,16 @@
 
             (when preview?
               (ui/tooltip
-                (ui/button [:span (t :flashcards/modal-btn-reset)]
-                  :id "card-reset"
-                  :class (util/hiccup->class "opacity-60.hover:opacity-100.card-reset")
-                  :on-click (fn [e]
-                              (util/stop e)
-                              (operation-reset! card)))
-
-                [:div.text-sm
-                 (t :flashcards/modal-btn-reset-tip)]
-                {:trigger-props {:as-child false}}))]
+               (ui/button [:span (t :flashcards/modal-btn-reset)]
+                          :id "card-reset"
+                          :class (util/hiccup->class "opacity-60.hover:opacity-100.card-reset")
+                          :on-click (fn [e]
+                                      (util/stop e)
+                                      (operation-reset! card)))
+
+               [:div.text-sm
+                (t :flashcards/modal-btn-reset-tip)]
+               {:trigger-props {:as-child false}}))]
            [:div.my-3 (ui/button "Review cards" :small? true)])]))))
 
 (rum/defc view-modal <
@@ -631,17 +631,17 @@
            ;; FIXME: CSS issue
            (if @*preview-mode?
              (ui/tooltip
-               [:div.opacity-60.text-sm.mr-2
-                @*card-index
-                [:span "/"]
-                total]
-               [:div.text-sm (t :flashcards/modal-current-total)])
+              [:div.opacity-60.text-sm.mr-2
+               @*card-index
+               [:span "/"]
+               total]
+              [:div.text-sm (t :flashcards/modal-current-total)])
              (ui/tooltip
-               [:div.opacity-60.text-sm.mr-2
-                (max 0 (- filtered-total @*card-index))
-                [:span "/"]
-                total]
-               [:div.text-sm (t :flashcards/modal-overdue-total)]))
+              [:div.opacity-60.text-sm.mr-2
+               (max 0 (- filtered-total @*card-index))
+               [:span "/"]
+               total]
+              [:div.text-sm (t :flashcards/modal-overdue-total)]))
 
            (ui/tooltip
             (ui/button
@@ -656,8 +656,8 @@
                :small? true}
               (when @*preview-mode?
                 {:icon-props {:style {:color "var(--ls-button-background)"}}})))
-             [:div.text-sm (t :flashcards/modal-toggle-preview-mode)]
-             {:trigger-props {:as-child false}})
+            [:div.text-sm (t :flashcards/modal-toggle-preview-mode)]
+            {:trigger-props {:as-child false}})
 
            (ui/tooltip
             (ui/button
@@ -670,8 +670,8 @@
                :small? true}
               (when @*random-mode?
                 {:icon-props {:style {:color "var(--ls-button-background)"}}})))
-             [:div.text-sm (t :flashcards/modal-toggle-random-mode)]
-             {:trigger-props {:as-child false}})]]
+            [:div.text-sm (t :flashcards/modal-toggle-random-mode)]
+            {:trigger-props {:as-child false}})]]
          [:div.px-1
           (when (and (not modal?) (not @*preview-mode?))
             {:on-click (fn []

+ 2 - 0
src/main/frontend/handler/events.cljs

@@ -14,6 +14,7 @@
             [frontend.db :as db]
             [frontend.db.async :as db-async]
             [frontend.db.model :as db-model]
+            [frontend.db.react :as react]
             [frontend.db.transact :as db-transact]
             [frontend.extensions.fsrs :as fsrs]
             [frontend.fs :as fs]
@@ -83,6 +84,7 @@
 
 (defn- graph-switch
   [graph]
+  (react/clear-query-state!)
   (let [db-based? (config/db-based-graph? graph)]
     (state/set-current-repo! graph)
     (page-handler/init-commands!)

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

@@ -930,8 +930,7 @@
                                      :rootMargin (str root-margin "px")
                                      :triggerOnce trigger-once?
                                      :onChange (fn [in-view? _entry]
-                                                 (when-not (= in-view? visible?)
-                                                   (set-visible! in-view?)))})
+                                                 (set-visible! in-view?))})
          ref (.-ref inViewState)]
      (lazy-visible-inner visible? content-fn ref fade-in? placeholder))))
 

+ 3 - 3
src/test/frontend/db/query_custom_test.cljs

@@ -1,8 +1,8 @@
 (ns frontend.db.query-custom-test
   (:require [cljs.test :refer [deftest is use-fixtures testing]]
-            [frontend.test.helper :as test-helper :refer [load-test-files]]
             [frontend.db.query-custom :as query-custom]
-            [frontend.db.react :as react]))
+            [frontend.db.react :as react]
+            [frontend.test.helper :as test-helper :refer [load-test-files]]))
 
 (use-fixtures :each {:before test-helper/start-test-db!
                      :after test-helper/destroy-test-db!})
@@ -10,7 +10,7 @@
 (defn- custom-query
   [query]
   (react/clear-query-state!)
-  (when-let [result (query-custom/custom-query test-helper/test-db query {})]
+  (when-let [result (last (query-custom/custom-query test-helper/test-db query {}))]
     (map first (deref result))))
 
 (deftest custom-query-test

+ 14 - 15
src/test/frontend/db/query_react_test.cljs

@@ -1,11 +1,11 @@
 (ns frontend.db.query-react-test
-  (:require [cljs.test :refer [deftest is use-fixtures]]
-            [cljs-time.core :as t]
+  (:require [cljs-time.core :as t]
+            [cljs.test :refer [deftest is use-fixtures]]
             [clojure.string :as string]
-            [logseq.db.frontend.inputs :as db-inputs]
-            [frontend.test.helper :as test-helper :refer [load-test-files]]
             [frontend.db.query-custom :as query-custom]
-            [goog.string :as gstring]))
+            [frontend.test.helper :as test-helper :refer [load-test-files]]
+            [goog.string :as gstring]
+            [logseq.db.frontend.inputs :as db-inputs]))
 
 (use-fixtures :each {:before test-helper/start-test-db!
                      :after test-helper/destroy-test-db!})
@@ -14,7 +14,7 @@
   "Use custom-query over react-query for testing since it tests react-query and
 adds rules that users often use"
   [query & [opts]]
-  (when-let [result (query-custom/custom-query test-helper/test-db query opts)]
+  (when-let [result (last (query-custom/custom-query test-helper/test-db query opts))]
     (map first (deref result))))
 
 (defn- blocks-created-between-inputs [a b]
@@ -31,17 +31,16 @@ adds rules that users often use"
                                 [(>= ?timestamp ?start)]
                                 [(<= ?timestamp ?end)]]}))))
 
-
 (defn- blocks-with-tag-on-specified-current-page [& {:keys [current-page tag]}]
   (map :block/title (custom-query {:title "Query title"
-                                     :inputs [:current-page tag]
-                                     :query '[:find (pull ?b [*])
-                                              :in $ ?current-page ?tag-name
-                                              :where [?b :block/page ?bp]
-                                              [?bp :block/name ?current-page]
-                                              [?b :block/ref-pages ?t]
-                                              [?t :block/name ?tag-name]]}
-                                    {:current-page-fn (constantly current-page)})))
+                                   :inputs [:current-page tag]
+                                   :query '[:find (pull ?b [*])
+                                            :in $ ?current-page ?tag-name
+                                            :where [?b :block/page ?bp]
+                                            [?bp :block/name ?current-page]
+                                            [?b :block/ref-pages ?t]
+                                            [?t :block/name ?tag-name]]}
+                                  {:current-page-fn (constantly current-page)})))
 
 ;; These tests rely on seeding timestamps with properties. If this ability goes
 ;; away we could still test page-level timestamps

+ 2 - 2
src/test/frontend/test/fixtures.cljs

@@ -8,9 +8,9 @@
 
 (defn react-components
   [f]
-  (reset! react/query-state {})
+  (reset! react/*query-state {})
   (let [r (f)]
-    (reset! react/query-state {})
+    (reset! react/*query-state {})
     r))
 
 (defn- reset-datascript