Przeglądaj źródła

perf: no need to transact property values to ui db

Tienson Qin 6 miesięcy temu
rodzic
commit
572d6f4390

+ 52 - 30
deps/db/src/logseq/db/frontend/view.cljs

@@ -113,17 +113,17 @@
       (sort-by-multiple-properties db sorting rows))))
 
 (defn get-property-value-content
-  [db entity]
-  (when entity
+  [db value]
+  (when value
     (cond
-      (uuid? entity)
-      (db-property/property-value-content (d/entity db [:block/uuid entity]))
-      (de/entity? entity)
-      (db-property/property-value-content entity)
-      (keyword? entity)
-      (str entity)
+      (uuid? value)
+      (db-property/property-value-content (d/entity db [:block/uuid value]))
+      (de/entity? value)
+      (db-property/property-value-content value)
+      (keyword? value)
+      (str value)
       :else
-      entity)))
+      value)))
 
 (defn- ^:large-vars/cleanup-todo row-matched?
   [db row filters input]
@@ -379,27 +379,49 @@
     (get-entities db view feat-type index-attr view-for-id)))
 
 (defn get-property-values
-  [db view-id property-ident]
-  (let [entities-result (get-view-entities db view-id)
-        entities (if (map? entities-result)
-                   (:ref-blocks entities-result)
-                   entities-result)
-        values (->> (mapcat (fn [entity]
-                              (let [v (get entity property-ident)]
-                                (if (set? v) v #{v})))
-                            entities)
-                    (remove nil?))]
-    (->>
-     (keep (fn [e]
-             (let [label (get-property-value-content db e)]
-               (when-not (string/blank? (str label))
-                 {:label (str label)
-                  :value (if (de/entity? e)
-                           (select-keys e [:db/id :block/uuid])
-                           e)})))
-           values)
-     (common-util/distinct-by :label)
-     (sort-by :label))))
+  [db property-ident {:keys [view-id]}]
+  (let [property (d/entity db property-ident)
+        default-value (:logseq.property/default-value property)
+        empty-id (:db/id (d/entity db :logseq.property/empty-placeholder))
+        ref-type? (= :db.type/ref (:db/valueType property))
+        values (if view-id
+                 (let [entities-result (get-view-entities db view-id)
+                       entities (if (map? entities-result)
+                                  (:ref-blocks entities-result)
+                                  entities-result)]
+                   (->> (mapcat (fn [entity]
+                                  (let [v (get entity property-ident)]
+                                    (if (set? v) v #{v})))
+                                entities)
+                        (remove nil?)
+                        (keep (fn [e]
+                                (when-let [label (get-property-value-content db e)]
+                                  (when-not (or (string/blank? (str label))
+                                                (= empty-id (:db/id e)))
+                                    {:label (str label)
+                                     :value (if (de/entity? e)
+                                              (select-keys e [:db/id :block/uuid])
+                                              e)}))))
+                        (common-util/distinct-by :label)))
+                 ;; get all values
+                 (->> (d/datoms db :avet property-ident)
+                      (map (fn [d]
+                             (:v d)))
+                      distinct
+                      (map (fn [v]
+                             (let [e (when ref-type? (d/entity db v))
+                                   [label value] (if ref-type?
+                                                   [(db-property/property-value-content e)
+                                                    (select-keys e [:db/id :block/uuid])]
+                                                   [(str v) v])]
+                               {:label label
+                                :value value})))
+                      (common-util/distinct-by :label)))]
+    (if default-value
+      (cons {:label (get-property-value-content db default-value)
+             :value (select-keys default-value [:db/id :block/uuid])}
+            values)
+      values)))
 
 (defn get-view-data
   [db view-id {:keys [journals? _view-for-id view-feature-type input]

+ 36 - 44
src/main/frontend/components/property/config.cljs

@@ -363,27 +363,19 @@
 
 (rum/defc add-existing-values
   [property values {:keys [toggle-fn]}]
-  (let [uuid-values? (every? uuid? values)
-        values' (if uuid-values?
-                  (let [values' (map #(db/entity [:block/uuid %]) values)]
-                    (->> values'
-                         (util/distinct-by db-property/closed-value-content)
-                         (map :block/uuid)))
-                  values)]
-    [:div.flex.flex-col.gap-1.w-64.p-4.overflow-y-auto
-     {:class "max-h-[50dvh]"}
-     [:div "Existing values:"]
-     [:ol
-      (for [value values']
-        [:li (if (uuid? value)
-               (let [result (db/entity [:block/uuid value])]
-                 (db-property/closed-value-content result))
-               (str value))])]
-     (shui/button
-      {:on-click (fn []
-                   (p/let [_ (db-property-handler/add-existing-values-to-closed-values! (:db/id property) values')]
-                     (toggle-fn)))}
-      "Add choices")]))
+  [:div.flex.flex-col.gap-1.w-64.p-4.overflow-y-auto
+   {:class "max-h-[50dvh]"}
+   [:div "Existing values:"]
+   [:ol
+    (for [value values]
+      [:li (:label value)])]
+   (shui/button
+    {:on-click (fn []
+                 (p/let [_ (db-property-handler/add-existing-values-to-closed-values! (:db/id property)
+                                                                                      (map (fn [{:keys [value]}]
+                                                                                             (:block/uuid value)) values))]
+                   (toggle-fn)))}
+    "Add choices")])
 
 (rum/defc choices-sub-pane < rum/reactive db-mixins/query
   [property {:keys [disabled?] :as opts}]
@@ -431,29 +423,29 @@
         {:icon :plus :title "Add choice"
          :item-props {:on-click
                       (fn [^js e]
-                        (p/let [values (db-async/<get-block-property-values (state/get-current-repo) (:db/ident property))
+                        (p/let [values (db-async/<get-property-values (:db/ident property) {})
                                 existing-values (seq (:property/closed-values property))
-                                values (if (seq existing-values)
-                                         (let [existing-ids (set (map :db/id existing-values))]
-                                           (remove (fn [id] (existing-ids id)) values))
-                                         values)]
-                          (shui/popup-show! (.-target e)
-                                            (fn [{:keys [id]}]
-                                              (let [opts {:toggle-fn (fn [] (shui/popup-hide! id))}
-                                                    values' (->> (if (contains? db-property-type/all-ref-property-types (:logseq.property/type property))
-                                                                   (->> values
-                                                                        (map db/entity)
-                                                                        (remove (fn [e]
-                                                                                  (let [value (db-property/property-value-content e)]
-                                                                                    (and (string? value) (string/blank? value)))))
-                                                                        (map :block/uuid))
-                                                                   (remove string/blank? values))
-                                                                 distinct)]
-                                                (if (seq values')
-                                                  (add-existing-values property values' opts)
-                                                  (choice-base-edit-form property {:create? true}))))
-                                            {:id :ls-base-edit-form
-                                             :align "start"})))}}))]))
+                                values' (if (seq existing-values)
+                                          (let [existing-ids (set (map :db/id existing-values))
+                                                existing-titles (set (map db-property/property-value-content existing-values))]
+                                            (remove (fn [{:keys [label value]}]
+                                                      (or (existing-ids (:db/id value))
+                                                          (existing-titles label)
+                                                          (string/blank? label))) values))
+                                          (remove (fn [{:keys [label _value]}]
+                                                    (string/blank? label))
+                                                  values))]
+                          (p/do!
+                           (when (seq values')
+                             (db-async/<get-blocks (state/get-current-repo) (map (fn [{:keys [value]}] (:db/id value)) values)))
+                           (shui/popup-show! (.-target e)
+                                             (fn [{:keys [id]}]
+                                               (let [opts {:toggle-fn (fn [] (shui/popup-hide! id))}]
+                                                 (if (seq values')
+                                                   (add-existing-values property values' opts)
+                                                   (choice-base-edit-form property {:create? true}))))
+                                             {:id :ls-base-edit-form
+                                              :align "start"}))))}}))]))
 
 (rum/defc checkbox-state-mapping
   [choices]
@@ -766,7 +758,7 @@
                  property (first (:rum/args state))
                  ident (:db/ident property)]
              (p/let [_ (db-async/<get-block repo (:block/uuid property))
-                     result (db-async/<get-block-property-values repo ident)]
+                     result (db-async/<get-property-values ident)]
                (reset! *values result))
              (assoc state ::values *values)))}
   [state property* owner-block opts]

+ 9 - 20
src/main/frontend/components/property/value.cljs

@@ -236,6 +236,11 @@
   [block property value selected? {:keys [refresh-result-f] :as opts}]
   (let [many? (db-property/many? property)
         blocks (get-operating-blocks block)]
+    (when (and selected?
+               (= :db.type/ref (:db/valueType property))
+               (number? value)
+               (not (db/entity value)))
+      (db-async/<get-block (state/get-current-repo) value {:children? false}))
     (p/do!
      (if selected?
        (<add-property! block (:db/ident property) value
@@ -827,14 +832,7 @@
                                       (p/let [property-ident (if (= :logseq.property/default-value (:db/ident property))
                                                                (:db/ident block)
                                                                (:db/ident property))
-                                              result (db-async/<get-block-property-values (state/get-current-repo)
-                                                                                          property-ident)
-                                              non-loaded-ids (filter (fn [id] (not (db/entity id))) result)
-                                              repo (state/get-current-repo)
-                                              _ (p/all (map (fn [id] (db-async/<get-block repo id
-                                                                                          {:children? false
-                                                                                           :including-property-vals? false
-                                                                                           :skip-refresh? true})) non-loaded-ids))]
+                                              result (db-async/<get-property-values property-ident)]
                                         (reset! *values result))))]
              (refresh-result-f)
              (assoc state
@@ -849,7 +847,6 @@
     (when-not (= :loading values)
       (let [type (:logseq.property/type property)
             closed-values? (seq (:property/closed-values property))
-            ref-type? (db-property-type/all-ref-property-types type)
             items (if closed-values?
                     (let [date? (and
                                  (= (:db/ident property) :logseq.task/recur-unit)
@@ -869,17 +866,9 @@
                                  :label-value value}))
                             values))
                     (->> values
-                         (mapcat (fn [value]
-                                   (if (coll? value)
-                                     (map (fn [v] {:value v}) value)
-                                     [{:value value}])))
-                         (map (fn [{:keys [value]}]
-                                (if (and ref-type? (number? value))
-                                  (when-let [e (db/entity value)]
-                                    {:label (db-property/property-value-content e)
-                                     :value value})
-                                  {:label value
-                                   :value value})))
+                         (map (fn [{:keys [value label]}]
+                                {:label label
+                                 :value (:db/id value)}))
                          (distinct)))
             items (->> (if (= :date type)
                          (map (fn [m] (let [label (:block/title (db/entity (:value m)))]

+ 20 - 33
src/main/frontend/components/query/builder.cljs

@@ -172,55 +172,42 @@
 
 (rum/defc property-value-select-inner
   < rum/reactive db-mixins/query
-  [repo *property *private-property? *find *tree opts loc values {:keys [db-graph? ref-property? property-type]}]
-  (let [;; FIXME: lazy load property values consistently on first call
-        ;; Guard against non ref properties like :logseq.property/icon
-        _ (when (and db-graph? ref-property?)
-            (doseq [id values] (db/sub-block id)))
-        values' (if db-graph?
-                  (if ref-property?
-                    (map #(db-property/property-value-content (db/entity repo %)) values)
-                    (if (contains? #{:checkbox :keyword :raw-number :string} property-type)
-                      values
-                      ;; Don't display non-ref property values as they don't have display and query support
-                      []))
-                  values)
-        values'' (map #(hash-map :value (str %)
-                                   ;; Preserve original-value as some values like boolean do not display in select
-                                 :original-value %)
-                      (cons "Select all" values'))]
-    (select values''
-            (fn [{:keys [original-value]}]
+  [*property *private-property? *find *tree opts loc values {:keys [db-graph?]}]
+  (let [values' (cons {:label "Select all"
+                       :value "Select all"}
+                      values)]
+    (select values'
+            (fn [{:keys [value]}]
               (let [k (cond
                         db-graph? (if @*private-property? :private-property :property)
                         (= (rum/react *find) :page) :page-property
                         :else :property)
-                    x (if (= original-value "Select all")
+                    x (if (= value "Select all")
                         [k @*property]
-                        [k @*property original-value])]
+                        [k @*property value])]
                 (reset! *property nil)
                 (append-tree! *tree opts loc x))))))
 
 (rum/defc property-value-select
   [repo *property *private-property? *find *tree opts loc]
   (let [db-graph? (sqlite-util/db-based-graph? repo)
-        property-type (when db-graph? (:logseq.property/type (db/entity repo @*property)))
-        ref-property? (and db-graph? (contains? db-property-type/all-ref-property-types property-type))
         [values set-values!] (rum/use-state nil)]
     (hooks/use-effect!
-     (fn []
+     (fn [_property]
        (p/let [result (if db-graph?
-                        (db-async/<get-block-property-values repo @*property)
-                        (db-async/<file-get-property-values repo @*property))]
-         (when (and db-graph? ref-property?)
-           (doseq [db-id result]
-             (db-async/<get-block repo db-id :children? false)))
+                        (p/let [result (db-async/<get-property-values @*property)]
+                          (map (fn [{:keys [label _value]}]
+                                 {:label label
+                                  :value label})
+                               result))
+                        (p/let [result (db-async/<file-get-property-values repo @*property)]
+                          (map (fn [value]
+                                 {:label (str value)
+                                  :value value}) result)))]
          (set-values! result)))
      [@*property])
-    (property-value-select-inner repo *property *private-property? *find *tree opts loc values
-                                 {:db-graph? db-graph?
-                                  :ref-property? ref-property?
-                                  :property-type property-type})))
+    (property-value-select-inner *property *private-property? *find *tree opts loc values
+                                 {:db-graph? db-graph?})))
 
 (rum/defc tags
   [repo *tree opts loc]

+ 2 - 3
src/main/frontend/components/views.cljs

@@ -39,7 +39,6 @@
             [logseq.db.frontend.property :as db-property]
             [logseq.db.frontend.view :as db-view]
             [logseq.shui.ui :as shui]
-            [medley.core :as medley]
             [promesa.core :as p]
             [rum.core :as rum]))
 
@@ -709,7 +708,7 @@
     (hooks/use-effect!
      (fn []
        (when (and view-entity property-ident (not (or timestamp? checkbox?)))
-         (p/let [data (get-property-values (:db/id view-entity) property-ident)]
+         (p/let [data (db-async/<get-property-values property-ident {:view-id (:db/id view-entity)})]
            (set-values! data))))
      [property-ident])
     (let [option (cond
@@ -911,7 +910,7 @@
          (when (seq ids) (db-async/<get-blocks (state/get-current-repo) ids)))
        (when (and property-ident dropdown-open?
                   (not (contains? #{:data :datetime :checkbox} type)))
-         (p/let [data (get-property-values (:db/id view-entity) property-ident)]
+         (p/let [data (db-async/<get-property-values property-ident {:view-id (:db/id view-entity)})]
            (set-values! (map (fn [v] (if (map? (:value v))
                                        (assoc v :value (:block/uuid (:value v)))
                                        v)) data)))))

+ 7 - 17
src/main/frontend/db/async.cljs

@@ -91,25 +91,15 @@
   (when-not (config/db-based-graph? graph)
     (file-async/<get-file-based-property-values graph property)))
 
-(defn <get-block-property-values
+(defn <get-property-values
   "For db graphs, returns property value ids for given property db-ident.
    Separate from file version because values are lazy loaded"
-  [graph property-id]
-  (let [default-value-id (:db/id (:logseq.property/default-value (db/entity property-id)))
-        empty-id (:db/id (db/entity :logseq.property/empty-placeholder))]
-    (p/let [result (<q graph {:transact-db? false}
-                       '[:find [?v ...]
-                         :in $ ?property-id ?empty-id
-                         :where
-                         [?b ?property-id ?v]
-                         [(not= ?v ?empty-id)]]
-                       property-id
-                       empty-id)]
-      (distinct
-       (if default-value-id
-        ;; put default value the first
-         (cons default-value-id result)
-         result)))))
+  [property-id & {:keys [view-id]}]
+  (when property-id
+    (p/let [data-str (.get-property-values ^js @state/*db-worker (state/get-current-repo)
+                                           (ldb/write-transit-str {:view-id view-id
+                                                                   :property-ident property-id}))]
+      (ldb/read-transit-str data-str))))
 
 (defonce *block-cache (atom (cache/lru-cache-factory {} :threshold 1000)))
 (defn <get-block

+ 2 - 1
src/main/frontend/worker/db_worker.cljs

@@ -919,7 +919,8 @@
    [_this repo opts-str]
    (let [conn (worker-state/get-datascript-conn repo)
          {:keys [view-id property-ident]} (ldb/read-transit-str opts-str)
-         data (db-view/get-property-values @conn view-id property-ident)]
+         data (db-view/get-property-values @conn property-ident
+                                           {:view-id view-id})]
      (ldb/write-transit-str data)))
 
   (dangerousRemoveAllDbs