Browse Source

Merge branch 'feat/db' into enhance/plugin-web

charlie 1 year ago
parent
commit
91ef984f7a

+ 2 - 2
.carve/ignore

@@ -80,11 +80,11 @@ frontend.ui/_emoji-init-data
 frontend.worker.rtc.op-mem-layer/_sync-loop-canceler
 ;; Used by shadow.cljs
 frontend.worker.db-worker/init
-;; WIP fn, remove when it's ready
-frontend.worker.rtc.asset-sync/<loop-for-assets-sync
 ;; Future use?
 frontend.worker.rtc.hash/hash-blocks
 ;; Repl fn
 frontend.rum/use-atom-in
 ;; missionary utils
 frontend.common.missionary-util/<!
+;; Not sure why carve said it's unused...
+frontend.flows/current-repo-flow

+ 7 - 7
deps/db/src/logseq/db.cljs

@@ -3,22 +3,22 @@
    For shared file graph only fns, use logseq.graph-parser.db"
   (:require [clojure.set :as set]
             [clojure.string :as string]
+            [clojure.walk :as walk]
             [datascript.core :as d]
             [datascript.impl.entity :as de]
             [logseq.common.config :as common-config]
             [logseq.common.util :as common-util]
+            [logseq.common.util.namespace :as ns-util]
+            [logseq.common.util.page-ref :as page-ref]
             [logseq.common.uuid :as common-uuid]
             [logseq.db.frontend.class :as db-class]
             [logseq.db.frontend.delete-blocks :as delete-blocks] ;; Load entity extensions
-            [logseq.db.frontend.entity-plus]
+            [logseq.db.frontend.entity-plus :as entity-plus]
             [logseq.db.frontend.entity-util :as entity-util]
+            [logseq.db.frontend.property :as db-property]
             [logseq.db.frontend.rules :as rules]
             [logseq.db.sqlite.common-db :as sqlite-common-db]
-            [logseq.db.sqlite.util :as sqlite-util]
-            [logseq.db.frontend.property :as db-property]
-            [logseq.common.util.namespace :as ns-util]
-            [logseq.common.util.page-ref :as page-ref]
-            [clojure.walk :as walk])
+            [logseq.db.sqlite.util :as sqlite-util])
   (:refer-clojure :exclude [object?]))
 
 (defonce *transact-fn (atom nil))
@@ -192,7 +192,7 @@
 
 (def get-first-page-by-name sqlite-common-db/get-first-page-by-name)
 
-(def db-based-graph? entity-util/db-based-graph?)
+(def db-based-graph? entity-plus/db-based-graph?)
 
 (defn page-exists?
   "Returns truthy value if page exists.

+ 3 - 2
deps/db/src/logseq/db/frontend/content.cljs

@@ -4,7 +4,8 @@
             [logseq.common.util.page-ref :as page-ref]
             [datascript.core :as d]
             [logseq.common.util :as common-util]
-            [logseq.db.frontend.entity-util :as entity-util]))
+            [logseq.db.frontend.entity-util :as entity-util]
+            [logseq.db.frontend.entity-plus :as entity-plus]))
 
 ;; [[uuid]]
 (def id-ref-pattern
@@ -121,7 +122,7 @@
 (defn update-block-content
   "Replace `[[internal-id]]` with `[[page name]]`"
   [db item eid]
-  (if (entity-util/db-based-graph? db)
+  (if (entity-plus/db-based-graph? db)
     (if-let [content (:block/title item)]
       (let [refs (:block/refs (d/entity db eid))]
         (assoc item :block/title (id-ref->title-ref content refs false)))

+ 3 - 2
deps/db/src/logseq/db/frontend/delete_blocks.cljs

@@ -5,7 +5,8 @@
             [logseq.common.util.page-ref :as page-ref]
             [datascript.core :as d]
             [clojure.string :as string]
-            [logseq.db.frontend.entity-util :as entity-util]))
+            [logseq.db.frontend.entity-util :as entity-util]
+            [logseq.db.frontend.entity-plus :as entity-plus]))
 
 (defn- replace-ref-with-deleted-block-title
   [block ref-raw-title]
@@ -57,7 +58,7 @@
     (when (seq retracted-block-ids)
       (let [retracted-blocks (map #(d/entity db %) retracted-block-ids)
             retracted-tx (build-retracted-tx retracted-blocks)
-            macros-tx (when-not (entity-util/db-based-graph? db)
+            macros-tx (when-not (entity-plus/db-based-graph? db)
                         (mapcat (fn [b]
                                   ;; Only delete if last reference
                                   (keep #(when (<= (count (:block/_macros (d/entity db (:db/id %))))

+ 73 - 14
deps/db/src/logseq/db/frontend/entity_plus.cljc

@@ -5,23 +5,80 @@
   ;; Disable clj linters since we don't support clj
   #?(:clj {:clj-kondo/config {:linters {:unresolved-namespace {:level :off}
                                         :unresolved-symbol {:level :off}}}})
-  (:require [cljs.core]
-            #?(:org.babashka/nbb [datascript.db])
+  (:require #?(:org.babashka/nbb [datascript.db])
+            [cljs.core]
+            [datascript.core :as d]
             [datascript.impl.entity :as entity :refer [Entity]]
-            [logseq.db.frontend.content :as db-content]
-            [logseq.db.frontend.property :as db-property]
-            [logseq.db.frontend.entity-util :as entity-util]
+            [frontend.common.missionary-util :as c.m]
+            [frontend.flows :as flows]
             [logseq.common.util.date-time :as date-time-util]
-            [datascript.core :as d]))
-
-(def db-based-graph? entity-util/db-based-graph?)
-
-(def lookup-entity @#'entity/lookup-entity)
+            [logseq.db.frontend.entity-util :as entity-util]
+            [logseq.db.frontend.property :as db-property]
+            [missionary.core :as m]))
+
+(def immutable-db-idents
+  "These db-ident entities are immutable,
+  it means `(db/entity :block/title)` always return same result"
+  #{:block/created-at :block/updated-at
+    :block/uuid :block/title :block/tags :block/name :block/format
+    :block/schema :block/path-refs :block/refs :block/tx-id :block/type
+    :block/page :block/parent :block/order :block/journal-day :block/closed-value-property
+    :block/link :block/marker :block/warning :block/collapsed? :block/deadline :block/scheduled :block/level
+    :block/pre-block? :block/heading-level
+
+    :block/_refs :logseq.property/_query
+
+    :block.temp/search? :block.temp/ast-title :block.temp/ast-body
+    :block.temp/fully-loaded? :block.temp/top? :block.temp/bottom?
+
+    :db/cardinality :db/ident :db/index :db/valueType
+
+    :logseq.kv/db-type
+
+    :logseq.property.node/display-type :logseq.property/icon
+    :logseq.property.asset/type :logseq.property.asset/checksum
+    :logseq.property/created-from-property
+
+    :logseq.class/Query :logseq.class/Journal :logseq.class/Cards :logseq.class/Task})
+
+(def ^:private lookup-entity @#'entity/lookup-entity)
+
+(def ^:private *seen-immutable-entities (volatile! {}))
+
+(defn reset-immutable-entities-cache!
+  []
+  (vreset! *seen-immutable-entities {}))
+
+(c.m/run-background-task
+ ::reset-immutable-entities-cache!
+ (m/reduce
+  (fn [_ repo]
+    (when (some? repo)
+      (prn :reset-immutable-entities-cache!)
+      (reset-immutable-entities-cache!)))
+  flows/current-repo-flow))
+
+(defn entity-memoized
+  [db eid]
+  (if (and (qualified-keyword? eid)
+           (contains? immutable-db-idents eid))
+    (if-let [e (find @*seen-immutable-entities eid)]
+      (val e)
+      (let [r (d/entity db eid)]
+        (vswap! *seen-immutable-entities assoc eid r)
+        r))
+    (d/entity db eid)))
+
+(defn db-based-graph?
+  "Whether the current graph is db-only"
+  [db]
+  (when db
+    (= "db" (:kv/value (entity-memoized db :logseq.kv/db-type)))))
 
 (defn- get-journal-title
   [db e]
   (date-time-util/int->journal-title (:block/journal-day e)
-                                     (:logseq.property.journal/title-format (d/entity db :logseq.class/Journal))))
+                                     (:logseq.property.journal/title-format (entity-memoized db :logseq.class/Journal))))
 
 (defn- get-block-title
   [^Entity e k default-value]
@@ -36,7 +93,7 @@
          (let [result (lookup-entity e k default-value)
                refs (:block/refs e)
                result' (if (and (string? result) refs)
-                         (db-content/id-ref->title-ref result refs search?)
+                         ((resolve 'logseq.db.frontend.content/id-ref->title-ref) result refs search?)
                          result)]
            (or result' default-value)))))))
 
@@ -51,7 +108,7 @@
        result
        ;; property default value
        (when (qualified-keyword? k)
-         (when-let [property (d/entity db k)]
+         (when-let [property (entity-memoized db k)]
            (let [schema (lookup-entity property :block/schema nil)]
              (if (= :checkbox (:type schema))
                (lookup-entity property :logseq.property/scalar-default-value nil)
@@ -107,7 +164,9 @@
   [^js this]
   (let [v @(.-cache this)
         v' (if (:block/title v)
-             (assoc v :block/title (db-content/id-ref->title-ref (:block/title v) (:block/refs this) (:block.temp/search? this)))
+             (assoc v :block/title
+                    ((resolve 'logseq.db.frontend.content/id-ref->title-ref)
+                     (:block/title v) (:block/refs this) (:block.temp/search? this)))
              v)]
     (concat (seq v')
             (seq (.-kv this)))))

+ 2 - 9
deps/db/src/logseq/db/frontend/entity_util.cljs

@@ -1,16 +1,9 @@
 (ns logseq.db.frontend.entity-util
   "Lower level entity util fns used across db namespaces"
-  (:require [datascript.core :as d]
-            [clojure.string :as string]
+  (:require [clojure.string :as string]
             [datascript.impl.entity :as de])
   (:refer-clojure :exclude [object?]))
 
-(defn db-based-graph?
-  "Whether the current graph is db-only"
-  [db]
-  (when db
-    (= "db" (:kv/value (d/entity db :logseq.kv/db-type)))))
-
 (defn- has-tag?
   [entity tag-ident]
   (let [tags (:block/tags entity)]
@@ -92,4 +85,4 @@
                      :logseq.class/Journal :journal
                      :logseq.class/Whiteboard :whiteboard
                      :logseq.class/Page :page}]
-    (set (map #(ident->type (:db/ident %)) (:block/tags entity)))))
+    (set (map #(ident->type (:db/ident %)) (:block/tags entity)))))

+ 10 - 9
deps/db/src/logseq/db/sqlite/common_db.cljs

@@ -1,15 +1,16 @@
 (ns logseq.db.sqlite.common-db
   "Common sqlite db fns for browser and node"
-  (:require [datascript.core :as d]
-            ["path" :as node-path]
+  (:require ["path" :as node-path]
+            [clojure.set :as set]
             [clojure.string :as string]
-            [logseq.db.sqlite.util :as sqlite-util]
-            [logseq.common.util.date-time :as date-time-util]
-            [logseq.common.util :as common-util]
+            [datascript.core :as d]
             [logseq.common.config :as common-config]
+            [logseq.common.util :as common-util]
+            [logseq.common.util.date-time :as date-time-util]
+            [logseq.db.frontend.entity-plus :as entity-plus]
             [logseq.db.frontend.entity-util :as entity-util]
-            [clojure.set :as set]
-            [logseq.db.frontend.order :as db-order]))
+            [logseq.db.frontend.order :as db-order]
+            [logseq.db.sqlite.util :as sqlite-util]))
 
 (defn- get-pages-by-name
   [db page-name]
@@ -81,7 +82,7 @@
 
 (defn- property-with-values
   [db block]
-  (when (entity-util/db-based-graph? db)
+  (when (entity-plus/db-based-graph? db)
     (let [block (d/entity db (:db/id block))]
       (->> (:block/properties block)
            vals
@@ -242,7 +243,7 @@
   "Returns current database schema and initial data.
    NOTE: This fn is called by DB and file graphs"
   [db]
-  (let [db-graph? (entity-util/db-based-graph? db)
+  (let [db-graph? (entity-plus/db-based-graph? db)
         _ (when db-graph?
             (reset! db-order/*max-key (db-order/get-max-order db)))
         schema (:schema db)

+ 5 - 3
deps/db/src/logseq/db/test/helper.cljs

@@ -1,9 +1,10 @@
 (ns ^:node-only logseq.db.test.helper
   "Main ns for providing test fns for DB graphs"
   (:require [datascript.core :as d]
+            [logseq.db.frontend.entity-plus :as entity-plus]
+            [logseq.db.frontend.schema :as db-schema]
             [logseq.db.sqlite.build :as sqlite-build]
-            [logseq.db.sqlite.create-graph :as sqlite-create-graph]
-            [logseq.db.frontend.schema :as db-schema]))
+            [logseq.db.sqlite.create-graph :as sqlite-create-graph]))
 
 (defn find-block-by-content
   "Find first block by exact block string or by fuzzier regex"
@@ -43,6 +44,7 @@
   []
   (let [conn (d/create-conn db-schema/schema-for-db-based-graph)
         _ (d/transact! conn (sqlite-create-graph/build-db-initial-data "{}"))]
+    (entity-plus/reset-immutable-entities-cache!)
     conn))
 
 (defn create-conn-with-blocks
@@ -50,4 +52,4 @@
   [opts]
   (let [conn (create-conn)
         _ (sqlite-build/create-blocks conn opts)]
-    conn))
+    conn))

+ 1 - 1
deps/outliner/src/logseq/outliner/property.cljs

@@ -439,7 +439,7 @@
 
 (defn- property-with-position?
   [db property-id block position]
-  (let [property (d/entity db property-id)
+  (let [property (entity-plus/entity-memoized db property-id)
         schema (:block/schema property)]
     (and
      (= (:position schema) position)

+ 6 - 5
deps/outliner/test/logseq/outliner/validate_test.cljs

@@ -1,8 +1,9 @@
 (ns logseq.outliner.validate-test
-  (:require [cljs.test :refer [deftest is are testing]]
+  (:require [cljs.test :refer [are deftest is testing]]
             [datascript.core :as d]
-            [logseq.outliner.validate :as outliner-validate]
-            [logseq.db.test.helper :as db-test]))
+            [logseq.db.frontend.entity-plus :as entity-plus]
+            [logseq.db.test.helper :as db-test]
+            [logseq.outliner.validate :as outliner-validate]))
 
 (deftest validate-block-title-unique-for-properties
   (let [conn (db-test/create-conn-with-blocks
@@ -99,8 +100,8 @@
       (is (thrown-with-msg?
             js/Error
             #"Can't change.*built-in"
-            (outliner-validate/validate-parent-property (d/entity @conn :logseq.class/Task)
-                                                        [(d/entity @conn :logseq.class/Cards)]))))))
+            (outliner-validate/validate-parent-property (entity-plus/entity-memoized @conn :logseq.class/Task)
+                                                        [(entity-plus/entity-memoized @conn :logseq.class/Cards)]))))))
 
 (deftest validate-tags-property
   (let [conn (db-test/create-conn-with-blocks

+ 7 - 7
deps/publishing/src/logseq/publishing/db.cljs

@@ -1,17 +1,17 @@
 (ns logseq.publishing.db
   "Provides db fns and associated util fns for publishing"
-  (:require [datascript.core :as d]
-            [logseq.db.frontend.rules :as rules]
-            [clojure.set :as set]
+  (:require [clojure.set :as set]
             [clojure.string :as string]
-            [logseq.db.frontend.entity-util :as entity-util]
-            [logseq.db.frontend.malli-schema :as db-malli-schema]))
+            [datascript.core :as d]
+            [logseq.db.frontend.entity-plus :as entity-plus]
+            [logseq.db.frontend.malli-schema :as db-malli-schema]
+            [logseq.db.frontend.rules :as rules]))
 
 (defn ^:api get-area-block-asset-url
   "Returns asset url for an area block used by pdf assets. This lives in this ns
   because it is used by this dep and needs to be independent from the frontend app"
   [db block page]
-  (let [db-based? (entity-util/db-based-graph? db)]
+  (let [db-based? (entity-plus/db-based-graph? db)]
     (when-some [uuid' (:block/uuid block)]
       (if db-based?
         (when-let [image (:logseq.property.pdf/hl-image block)]
@@ -105,7 +105,7 @@
 
 (defn- hl-type-area-fn
   [db]
-  (if (entity-util/db-based-graph? db)
+  (if (entity-plus/db-based-graph? db)
     (fn [datom]
       (and (= :logseq.property.pdf/hl-type (:a datom))
            (= (keyword (:v datom)) :area)))

+ 13 - 6
src/main/frontend/components/block.cljs

@@ -19,8 +19,8 @@
             [frontend.components.property.value :as pv]
             [frontend.components.query :as query]
             [frontend.components.query.builder :as query-builder-component]
-            [frontend.components.svg :as svg]
             [frontend.components.select :as select]
+            [frontend.components.svg :as svg]
             [frontend.config :as config]
             [frontend.context.i18n :refer [t]]
             [frontend.date :as date]
@@ -78,6 +78,7 @@
             [logseq.common.util.page-ref :as page-ref]
             [logseq.db :as ldb]
             [logseq.db.frontend.content :as db-content]
+            [logseq.db.frontend.entity-plus :as entity-plus]
             [logseq.graph-parser.block :as gp-block]
             [logseq.graph-parser.mldoc :as gp-mldoc]
             [logseq.graph-parser.text :as text]
@@ -2285,7 +2286,9 @@
          ;; highlight ref block (area)
          (when area? [(hl-ref)])
 
-         (when (and (seq block-ast-title) (ldb/class-instance? (db/entity :logseq.class/Cards) block))
+         (when (and (seq block-ast-title) (ldb/class-instance?
+                                           (entity-plus/entity-memoized (db/get-db) :logseq.class/Cards)
+                                           block))
            [(ui/tooltip
              (shui/button
               {:variant :ghost
@@ -2302,7 +2305,8 @@
   (let [collapsed? (:collapsed? config)
         block' (db/entity (:db/id block))
         node-display-type (:logseq.property.node/display-type block')
-        query? (ldb/class-instance? (db/entity :logseq.class/Query) block')
+        db (db/get-db)
+        query? (ldb/class-instance? (entity-plus/entity-memoized db :logseq.class/Query) block')
         query (:logseq.property/query block')
         advanced-query? (and query? (= :code node-display-type))]
     (cond
@@ -3278,7 +3282,8 @@
 (rum/defc query-property-cp < rum/reactive db-mixins/query
   [block config collapsed?]
   (let [block (db/entity (:db/id block))
-        query? (ldb/class-instance? (db/entity :logseq.class/Query) block)]
+        db (db/get-db)
+        query? (ldb/class-instance? (entity-plus/entity-memoized db :logseq.class/Query) block)]
     (when (and query? (not collapsed?))
       (let [query-id (:db/id (:logseq.property/query block))
             query (some-> query-id db/sub-block)
@@ -3497,7 +3502,7 @@
         (db-properties-cp config block {:in-block-container? true})])
 
      (when (and db-based? (not collapsed?) (not (or table? property?))
-                (ldb/class-instance? (db/entity :logseq.class/Query) block))
+                (ldb/class-instance? (entity-plus/entity-memoized (db/get-db) :logseq.class/Query) block))
        (let [query-block (:logseq.property/query (db/entity (:db/id block)))
              query-block (if query-block (db/sub-block (:db/id query-block)) query-block)
              query (:block/title query-block)
@@ -3506,7 +3511,9 @@
          [:div {:style {:padding-left 42}}
           (query/custom-query (wrap-query-components (assoc config
                                                             :dsl-query? (not advanced-query?)
-                                                            :cards? (ldb/class-instance? (db/entity :logseq.class/Cards) block)))
+                                                            :cards? (ldb/class-instance? (entity-plus/entity-memoized
+                                                                                          (db/get-db)
+                                                                                          :logseq.class/Cards) block)))
                               (if advanced-query? result {:builder nil
                                                           :query (query-builder-component/sanitize-q query)}))]))
 

+ 3 - 4
src/main/frontend/components/property.cljs

@@ -2,7 +2,6 @@
   "Block properties management."
   (:require [clojure.set :as set]
             [clojure.string :as string]
-            [dommy.core :as d]
             [frontend.components.dnd :as dnd]
             [frontend.components.icon :as icon-component]
             [frontend.components.property.config :as property-config]
@@ -10,16 +9,16 @@
             [frontend.components.property.value :as pv]
             [frontend.components.select :as select]
             [frontend.components.svg :as svg]
-            [frontend.handler.property.util :as pu]
             [frontend.config :as config]
             [frontend.db :as db]
-            [frontend.db.model :as db-model]
             [frontend.db-mixins :as db-mixins]
             [frontend.db.async :as db-async]
+            [frontend.db.model :as db-model]
             [frontend.handler.db-based.property :as db-property-handler]
+            [frontend.handler.editor :as editor-handler]
             [frontend.handler.notification :as notification]
+            [frontend.handler.property.util :as pu]
             [frontend.handler.route :as route-handler]
-            [frontend.handler.editor :as editor-handler]
             [frontend.mixins :as mixins]
             [frontend.modules.shortcut.core :as shortcut]
             [frontend.state :as state]

+ 18 - 1
src/main/frontend/core.cljs

@@ -2,6 +2,7 @@
   "Entry ns for the mobile, browser and electron frontend apps"
   {:dev/always true}
   (:require [frontend.common-keywords]
+            [frontend.common.schema-register :as sr]
             [frontend.components.plugins :as plugins]
             [frontend.config :as config]
             [frontend.fs.sync :as sync]
@@ -11,7 +12,6 @@
             [frontend.log]
             [frontend.page :as page]
             [frontend.routes :as routes]
-            [frontend.common.schema-register :as sr]
             [frontend.spec]
             [logseq.api]
             [malli.dev.cljs :as md]
@@ -58,11 +58,28 @@
     (when config/dev?
       (js/setTimeout #(sync/<sync-start) 1000))))
 
+(comment
+  (def d-entity-count (volatile! 0))
+  (def ident->count (volatile! {}))
+  (def time-sum (volatile! 0))
+  (defn- setup-entity-profile!
+    []
+    (let [origin-d-entity d/entity]
+      (set! d/entity (fn [& args]
+                       (let [{r :result time :time} (util/with-time (apply origin-d-entity args))
+                             k (last args)]
+                         (vswap! d-entity-count inc)
+                         (vswap! ident->count update k inc)
+                         (vswap! time-sum #(+ time %))
+                         (println @d-entity-count (:db/id r) k (get @ident->count k) @time-sum "ms")
+                         r))))))
+
 (defn ^:export init []
   ;; init is called ONCE when the page loads
   ;; this is called in the index.html and must be exported
   ;; so it is available even in :advanced release builds
 
+  ;; (setup-entity-profile!)
   (plugin-handler/setup!
    #(handler/start! start)))
 

+ 12 - 3
src/main/frontend/db/rtc/debug_ui.cljs

@@ -3,6 +3,7 @@
   (:require [fipp.edn :as fipp]
             [frontend.common.missionary-util :as c.m]
             [frontend.db :as db]
+            [frontend.handler.db-based.rtc-flows :as rtc-flows]
             [frontend.handler.user :as user]
             [frontend.persist-db.browser :as db-browser]
             [frontend.state :as state]
@@ -15,7 +16,6 @@
             [rum.core :as rum]))
 
 (defonce debug-state (:rtc/state @state/state))
-(defonce rtc-log-flow (m/watch (:rtc/log @state/state)))
 
 (defn- stop
   []
@@ -37,7 +37,7 @@
                                          logs)]
                              (reset! (get state ::logs) logs*)
                              logs*))
-                         nil rtc-log-flow)
+                         nil rtc-flows/rtc-log-flow)
                         ::sub-logs)]
                    (reset! (get state ::sub-log-canceler) canceler)
                    state))
@@ -102,6 +102,7 @@
             :remote-graphs (:remote-graphs debug-state*)
             :online-users (:online-users debug-state*)
             :auto-push? (:auto-push? debug-state*)
+            :remote-profile? (:remote-profile? debug-state*)
             :current-page (state/get-current-page)
             :blocks-count (when-let [page (state/get-current-page)]
                             (count (:block/_page (db/get-page page))))}
@@ -126,7 +127,15 @@
                               {:on-click
                                (fn []
                                  (let [^object worker @db-browser/*worker]
-                                   (.rtc-toggle-auto-push worker (state/get-current-repo))))})]
+                                   (.rtc-toggle-auto-push worker)))})]
+        [:div.mr-2 (ui/button (str "Toggle remote profile("
+                                   (if (:remote-profile? debug-state*)
+                                     "ON" "OFF")
+                                   ")")
+                              {:on-click
+                               (fn []
+                                 (let [^object worker @db-browser/*worker]
+                                   (.rtc-toggle-remote-profile worker)))})]
         [:div (shui/button
                {:variant :outline
                 :class "text-red-rx-09 border-red-rx-08 hover:text-red-rx-10"

+ 2 - 1
src/main/frontend/extensions/fsrs.cljs

@@ -18,6 +18,7 @@
             [frontend.ui :as ui]
             [frontend.util :as util]
             [logseq.db :as ldb]
+            [logseq.db.frontend.entity-plus :as entity-plus]
             [logseq.shui.ui :as shui]
             [missionary.core :as m]
             [open-spaced-repetition.cljc-fsrs.core :as fsrs.core]
@@ -247,7 +248,7 @@
         all-cards (concat
                    [{:db/id :global
                      :block/title "All cards"}]
-                   (db-model/get-class-objects repo (:db/id (db/entity :logseq.class/Cards))))
+                   (db-model/get-class-objects repo (:db/id (entity-plus/entity-memoized (db/get-db) :logseq.class/Cards))))
         *block-ids (::block-ids state)
         block-ids (rum/react *block-ids)
         loading? (rum/react (::loading? state))

+ 11 - 0
src/main/frontend/flows.cljs

@@ -0,0 +1,11 @@
+(ns frontend.flows
+  "This ns contains some event flows."
+  (:require [missionary.core :as m]))
+
+(def *current-repo (atom nil))
+
+(def current-repo-flow
+  "Like get-current-repo."
+  (m/eduction
+   (dedupe)
+   (m/watch *current-repo)))

+ 9 - 7
src/main/frontend/handler/editor.cljs

@@ -2,6 +2,7 @@
   (:require [clojure.set :as set]
             [clojure.string :as string]
             [clojure.walk :as w]
+            [datascript.core :as d]
             [dommy.core :as dom]
             [frontend.commands :as commands]
             [frontend.config :as config]
@@ -54,18 +55,18 @@
             [logseq.common.util.block-ref :as block-ref]
             [logseq.common.util.page-ref :as page-ref]
             [logseq.db :as ldb]
-            [logseq.db.frontend.schema :as db-schema]
+            [logseq.db.frontend.entity-plus :as entity-plus]
             [logseq.db.frontend.property :as db-property]
+            [logseq.db.frontend.schema :as db-schema]
             [logseq.graph-parser.block :as gp-block]
             [logseq.graph-parser.mldoc :as gp-mldoc]
             [logseq.graph-parser.property :as gp-property]
             [logseq.graph-parser.text :as text]
             [logseq.graph-parser.utf8 :as utf8]
             [logseq.outliner.core :as outliner-core]
-            [promesa.core :as p]
-            [rum.core :as rum]
             [logseq.outliner.property :as outliner-property]
-            [datascript.core :as d]))
+            [promesa.core :as p]
+            [rum.core :as rum]))
 
 ;; FIXME: should support multiple images concurrently uploading
 
@@ -3457,15 +3458,16 @@
 (defn- db-collapsable?
   [block]
   (let [class-properties (:classes-properties (outliner-property/get-block-classes-properties (db/get-db) (:db/id block)))
-        properties (->> (map :a (d/datoms (db/get-db) :eavt (:db/id block)))
-                        (map db/entity)
+        db (db/get-db)
+        properties (->> (map :a (d/datoms db :eavt (:db/id block)))
+                        (map (partial entity-plus/entity-memoized db))
                         (concat class-properties)
                         (remove (fn [e] (db-property/db-attribute-properties (:db/ident e))))
                         (remove outliner-property/property-with-other-position?)
                         (remove (fn [e] (:hide? (:block/schema e))))
                         (remove nil?))]
     (or (seq properties)
-        (ldb/class-instance? (db/entity :logseq.class/Query) block))))
+        (ldb/class-instance? (entity-plus/entity-memoized db :logseq.class/Query) block))))
 
 (defn collapsable?
   ([block-id]

+ 4 - 1
src/main/frontend/state.cljs

@@ -11,6 +11,7 @@
             [electron.ipc :as ipc]
             [frontend.db.conn-state :as db-conn-state]
             [frontend.db.transact :as db-transact]
+            [frontend.flows :as flows]
             [frontend.mobile.util :as mobile-util]
             [frontend.rum :as r]
             [frontend.spec.storage :as storage-spec]
@@ -21,6 +22,7 @@
             [goog.object :as gobj]
             [logseq.common.config :as common-config]
             [logseq.db :as ldb]
+            [logseq.db.frontend.entity-plus :as entity-plus]
             [logseq.db.sqlite.util :as sqlite-util]
             [logseq.shui.dialog.core :as shui-dialog]
             [logseq.shui.ui :as shui]
@@ -599,7 +601,7 @@ should be done through this fn in order to get global config and config defaults
   (let [repo (get-current-repo)]
     (if (sqlite-util/db-based-graph? repo)
       (when-let [conn (db-conn-state/get-conn repo)]
-        (get (d/entity @conn :logseq.class/Journal)
+        (get (entity-plus/entity-memoized @conn :logseq.class/Journal)
              :logseq.property.journal/title-format
              "MMM do, yyyy"))
       (common-config/get-date-formatter (get-config)))))
@@ -978,6 +980,7 @@ Similar to re-frame subscriptions"
 (defn set-current-repo!
   [repo]
   (swap! state assoc :git/current-repo repo)
+  (reset! flows/*current-repo repo)
   (if repo
     (storage/set :git/current-repo repo)
     (storage/remove :git/current-repo))

+ 4 - 0
src/main/frontend/worker/db_worker.cljs

@@ -755,6 +755,10 @@
    [this]
    (rtc-core/rtc-toggle-auto-push))
 
+  (rtc-toggle-remote-profile
+   [this]
+   (rtc-core/rtc-toggle-remote-profile))
+
   (rtc-grant-graph-access
    [this token graph-uuid target-user-uuids-str target-user-emails-str]
    (let [target-user-uuids (ldb/read-transit-str target-user-uuids-str)

+ 5 - 4
src/main/frontend/worker/handler/page/db_based/page.cljs

@@ -7,15 +7,16 @@
             [logseq.common.util.namespace :as ns-util]
             [logseq.db :as ldb]
             [logseq.db.frontend.class :as db-class]
+            [logseq.db.frontend.entity-plus :as entity-plus]
+            [logseq.db.frontend.entity-util :as entity-util]
+            [logseq.db.frontend.malli-schema :as db-malli-schema]
             [logseq.db.frontend.order :as db-order]
             [logseq.db.frontend.property.build :as db-property-build]
             [logseq.db.frontend.property.util :as db-property-util]
             [logseq.db.sqlite.util :as sqlite-util]
             [logseq.graph-parser.block :as gp-block]
             [logseq.graph-parser.text :as text]
-            [logseq.outliner.validate :as outliner-validate]
-            [logseq.db.frontend.entity-util :as entity-util]
-            [logseq.db.frontend.malli-schema :as db-malli-schema]))
+            [logseq.outliner.validate :as outliner-validate]))
 
 (defn- build-page-tx [conn properties page {:keys [whiteboard? class? tags]}]
   (when (:block/uuid page)
@@ -168,7 +169,7 @@
            skip-existing-page-check? false}
     :as options}]
   (let [db @conn
-        date-formatter (:logseq.property.journal/title-format (d/entity db :logseq.class/Journal))
+        date-formatter (:logseq.property.journal/title-format (entity-plus/entity-memoized db :logseq.class/Journal))
         title (sanitize-title title*)
         types (cond class?
                     #{:logseq.class/Tag}

+ 4 - 3
src/main/frontend/worker/rtc/client.cljs

@@ -326,7 +326,7 @@
 
 (defn new-task--push-local-ops
   "Return a task: push local updates"
-  [repo conn graph-uuid date-formatter get-ws-create-task add-log-fn]
+  [repo conn graph-uuid date-formatter get-ws-create-task *remote-profile? add-log-fn]
   (m/sp
     (let [block-ops-map-coll (client-op/get&remove-all-block-ops repo)]
       (when-let [block-uuid->remote-ops (not-empty (gen-block-uuid->remote-ops @conn block-ops-map-coll))]
@@ -336,8 +336,9 @@
           (let [local-tx (client-op/get-local-tx repo)
                 r (try
                     (m/? (ws-util/send&recv get-ws-create-task
-                                            {:action "apply-ops" :graph-uuid graph-uuid
-                                             :ops ops-for-remote :t-before (or local-tx 1)}))
+                                            (cond-> {:action "apply-ops" :graph-uuid graph-uuid
+                                                     :ops ops-for-remote :t-before (or local-tx 1)}
+                                              (true? @*remote-profile?) (assoc :profile true))))
                     (catch :default e
                       (rollback repo block-ops-map-coll)
                       (throw e)))]

+ 6 - 1
src/main/frontend/worker/rtc/const.cljs

@@ -78,6 +78,7 @@
   "TODO: split this mix schema to multiple ones"
   [:map
    [:req-id :string]
+   [:profile {:optional true} :map]
    [:t {:optional true} :int]
    [:t-before {:optional true} :int]
    [:failed-ops {:optional true} [:sequential to-ws-op-schema]]
@@ -172,7 +173,9 @@
        (fn [api-schema]
          (let [[api-name [type']] api-schema]
            (if (= :map type')
-             [api-name (vec (concat (second api-schema) [[:req-id :string] [:action :string]]))]
+             [api-name (vec (concat (second api-schema) [[:req-id :string]
+                                                         [:action :string]
+                                                         [:profile {:optional true} :boolean]]))]
              api-schema)))
        api-schema-seq)))))
 
@@ -190,12 +193,14 @@
         [:map
          [:req-id :string]
          [:action :string]
+         [:profile {:optional true} :boolean]
          [:graph-uuid :string]
          [:ops [:sequential to-ws-op-schema]]
          [:t-before :int]]
         [:map
          [:req-id :string]
          [:action :string]
+         [:profile {:optional true} :boolean]
          [:s3-key :string]]]]
       ["presign-put-temp-s3-obj"
        [:map]]

+ 29 - 12
src/main/frontend/worker/rtc/core.cljs

@@ -180,6 +180,7 @@
    & {:keys [auto-push? debug-ws-url] :or {auto-push? true}}]
   (let [ws-url                     (or debug-ws-url (ws-util/get-ws-url token))
         *auto-push?                (atom auto-push?)
+        *remote-profile?           (atom false)
         *last-calibrate-t          (atom nil)
         *online-users              (atom nil)
         *assets-sync-loop-canceler (atom nil)
@@ -195,10 +196,11 @@
         (r.asset/create-assets-sync-loop repo get-ws-create-task graph-uuid conn *auto-push?)
         mixed-flow                 (create-mixed-flow repo get-ws-create-task *auto-push? *online-users)]
     (assert (some? *current-ws))
-    {:rtc-state-flow     (create-rtc-state-flow (create-ws-state-flow *current-ws))
-     :*rtc-auto-push?    *auto-push?
-     :*online-users      *online-users
-     :onstarted-task     started-dfv
+    {:rtc-state-flow       (create-rtc-state-flow (create-ws-state-flow *current-ws))
+     :*rtc-auto-push?      *auto-push?
+     :*rtc-remote-profile? *remote-profile?
+     :*online-users        *online-users
+     :onstarted-task       started-dfv
      :rtc-loop-task
      (holding-rtc-lock
       started-dfv
@@ -225,7 +227,7 @@
                :local-update-check
                (m/? (r.client/new-task--push-local-ops
                      repo conn graph-uuid date-formatter
-                     get-ws-create-task add-log-fn))
+                     get-ws-create-task *remote-profile? add-log-fn))
 
                :online-users-updated
                (reset! *online-users (:online-users (:value event)))
@@ -246,16 +248,21 @@
             (when @*assets-sync-loop-canceler (@*assets-sync-loop-canceler))))))}))
 
 (def ^:private empty-rtc-loop-metadata
-  {:graph-uuid nil
+  {:repo nil
+   :graph-uuid nil
    :user-uuid nil
    :rtc-state-flow nil
    :*rtc-auto-push? nil
+   :*rtc-remote-profile? nil
    :*online-users nil
    :*rtc-lock nil
    :canceler nil
    :*last-stop-exception nil})
 
-(defonce ^:private *rtc-loop-metadata (atom empty-rtc-loop-metadata))
+(defonce ^:private *rtc-loop-metadata (atom empty-rtc-loop-metadata
+                                            :validator
+                                            (fn [v] (= (set (keys empty-rtc-loop-metadata))
+                                                       (set (keys v))))))
 
 ;;; ================ API ================
 (defn new-task--rtc-start
@@ -268,7 +275,7 @@
         (let [user-uuid (:sub (worker-util/parse-jwt token))
               config (worker-state/get-config repo)
               date-formatter (common-config/get-date-formatter config)
-              {:keys [rtc-state-flow *rtc-auto-push? rtc-loop-task *online-users onstarted-task]}
+              {:keys [rtc-state-flow *rtc-auto-push? *rtc-remote-profile? rtc-loop-task *online-users onstarted-task]}
               (create-rtc-loop graph-uuid repo conn date-formatter token)
               *last-stop-exception (atom nil)
               canceler (c.m/run-task rtc-loop-task :rtc-loop-task
@@ -283,6 +290,7 @@
                                             :user-uuid user-uuid
                                             :rtc-state-flow rtc-state-flow
                                             :*rtc-auto-push? *rtc-auto-push?
+                                            :*rtc-remote-profile? *rtc-remote-profile?
                                             :*online-users *online-users
                                             :*rtc-lock *rtc-lock
                                             :canceler canceler
@@ -303,6 +311,11 @@
   (when-let [*auto-push? (:*rtc-auto-push? @*rtc-loop-metadata)]
     (swap! *auto-push? not)))
 
+(defn rtc-toggle-remote-profile
+  []
+  (when-let [*rtc-remote-profile? (:*rtc-remote-profile? @*rtc-loop-metadata)]
+    (swap! *rtc-remote-profile? not)))
+
 (defn new-task--get-graphs
   [token]
   (let [{:keys [get-ws-create-task]} (gen-get-ws-create-map--memoized (ws-util/get-ws-url token))]
@@ -356,14 +369,15 @@
   (let [rtc-loop-metadata-flow (m/watch *rtc-loop-metadata)]
     (m/ap
       (let [{rtc-lock :*rtc-lock
-             :keys [repo graph-uuid user-uuid rtc-state-flow *rtc-auto-push? *online-users
-                    *last-stop-exception]}
+             :keys [repo graph-uuid user-uuid rtc-state-flow *rtc-auto-push? *rtc-remote-profile?
+                    *online-users *last-stop-exception]}
             (m/?< rtc-loop-metadata-flow)]
         (try
           (when (and repo rtc-state-flow *rtc-auto-push? rtc-lock)
             (m/?<
              (m/latest
-              (fn [rtc-state rtc-auto-push? rtc-lock online-users pending-local-ops-count local-tx remote-tx]
+              (fn [rtc-state rtc-auto-push? rtc-remote-profile?
+                   rtc-lock online-users pending-local-ops-count local-tx remote-tx]
                 {:graph-uuid graph-uuid
                  :user-uuid user-uuid
                  :unpushed-block-update-count pending-local-ops-count
@@ -372,9 +386,12 @@
                  :rtc-state rtc-state
                  :rtc-lock rtc-lock
                  :auto-push? rtc-auto-push?
+                 :remote-profile? rtc-remote-profile?
                  :online-users online-users
                  :last-stop-exception-ex-data (some-> *last-stop-exception deref ex-data)})
-              rtc-state-flow (m/watch *rtc-auto-push?) (m/watch rtc-lock) (m/watch *online-users)
+              rtc-state-flow
+              (m/watch *rtc-auto-push?) (m/watch *rtc-remote-profile?)
+              (m/watch rtc-lock) (m/watch *online-users)
               (client-op/create-pending-block-ops-count-flow repo)
               (rtc-log-and-state/create-local-t-flow graph-uuid)
               (rtc-log-and-state/create-remote-t-flow graph-uuid))))