datascript.cljc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. (ns frontend.modules.outliner.datascript
  2. #?(:clj (:require [clojure.core :as core]))
  3. #?(:cljs (:require-macros [frontend.modules.outliner.datascript]))
  4. #?(:cljs (:require [datascript.core :as d]
  5. [frontend.db.conn :as conn]
  6. [frontend.db :as db]
  7. [frontend.modules.outliner.pipeline :as pipelines]
  8. [frontend.modules.editor.undo-redo :as undo-redo]
  9. [frontend.state :as state]
  10. [frontend.config :as config]
  11. [logseq.graph-parser.util :as gp-util]
  12. [lambdaisland.glogi :as log]
  13. [frontend.search :as search]
  14. [clojure.string :as string]
  15. [frontend.util :as util]
  16. [frontend.util.property :as property])))
  17. #?(:cljs
  18. (defn new-outliner-txs-state [] (atom [])))
  19. #?(:cljs
  20. (defn outliner-txs-state?
  21. [state]
  22. (and
  23. (instance? cljs.core/Atom state)
  24. (coll? @state))))
  25. #?(:cljs
  26. (defn after-transact-pipelines
  27. [repo {:keys [_db-before _db-after _tx-data _tempids tx-meta] :as tx-report}]
  28. (when-not config/test?
  29. (pipelines/invoke-hooks tx-report)
  30. (when (or (:outliner/transact? tx-meta)
  31. (:whiteboard/transact? tx-meta))
  32. (undo-redo/listen-db-changes! tx-report))
  33. (search/sync-search-indice! repo tx-report))))
  34. #?(:cljs
  35. (defn- remove-nil-from-transaction
  36. [txs]
  37. (some->> (gp-util/remove-nils txs)
  38. (map (fn [x]
  39. (if (map? x)
  40. (update-vals x (fn [v]
  41. (if (vector? v)
  42. (remove nil? v)
  43. v)))
  44. x))))))
  45. #?(:cljs
  46. (defn get-tx-id
  47. [tx-report]
  48. (get-in tx-report [:tempids :db/current-tx])))
  49. #?(:cljs
  50. (defn update-block-refs
  51. [txs opts]
  52. (if-let [changed (:uuid-changed opts)]
  53. (let [{:keys [kept deleted]} changed
  54. kept-e (db/entity [:block/uuid kept])
  55. deleted-e (db/entity [:block/uuid deleted])
  56. kept-id (:db/id kept-e)
  57. deleted-id (:db/id deleted-e)
  58. kept-refs (:block/_refs kept-e)
  59. kept-path-refs (:block/_path-refs kept-e)
  60. deleted-refs (:block/_refs deleted-e)
  61. kept-refs-txs (mapcat (fn [ref]
  62. (let [id (:db/id ref)]
  63. [[:db/retract id :block/refs kept-id]
  64. [:db/add id :block/refs deleted-id]])) kept-refs)
  65. kept-path-refs-txs (mapcat (fn [ref]
  66. (let [id (:db/id ref)]
  67. [[:db/retract id :block/path-refs kept-id]
  68. [:db/add id :block/path-refs deleted-id]])) kept-path-refs)
  69. deleted-refs-txs (mapcat (fn [ref]
  70. (let [id (:db/id ref)
  71. new-content (string/replace (:block/content ref) (str deleted) (str kept))]
  72. [[:db/add id :block/content new-content]])) deleted-refs)]
  73. (concat txs kept-refs-txs kept-path-refs-txs deleted-refs-txs))
  74. txs)))
  75. #?(:cljs
  76. (defn replace-ref-with-content
  77. [txs opts]
  78. (if (and (= :delete-blocks (:outliner-op opts))
  79. (not (:uuid-changed opts)))
  80. (let [retracted-block-ids (->> (keep (fn [tx]
  81. (when (and (vector? tx)
  82. (= :db.fn/retractEntity (first tx)))
  83. (second tx))) txs))
  84. retracted-blocks (map db/entity retracted-block-ids)
  85. retracted-tx (->> (for [block retracted-blocks]
  86. (let [refs (:block/_refs block)]
  87. (map (fn [ref]
  88. (let [id (:db/id ref)
  89. block-content (property/remove-properties (:block/format block) (:block/content block))
  90. new-content (-> (:block/content ref)
  91. (string/replace (re-pattern (util/format "{{embed \\(\\(%s\\)\\)\\s?}}" (str (:block/uuid block))))
  92. block-content)
  93. (string/replace (util/format "((%s))" (str (:block/uuid block)))
  94. block-content))]
  95. {:tx [[:db/retract (:db/id ref) :block/refs (:db/id block)]
  96. [:db/add id :block/content new-content]]
  97. :revert-tx [[:db/add (:db/id ref) :block/refs (:db/id block)]
  98. [:db/add id :block/content (:block/content ref)]]})) refs)))
  99. (apply concat))
  100. retracted-tx' (mapcat :tx retracted-tx)
  101. revert-tx (mapcat :revert-tx retracted-tx)]
  102. (when (seq retracted-tx')
  103. (state/set-state! [:editor/last-replace-ref-content-tx (state/get-current-repo)]
  104. {:retracted-block-ids retracted-block-ids
  105. :revert-tx revert-tx}))
  106. (concat txs retracted-tx'))
  107. txs)))
  108. #?(:cljs
  109. (defn transact!
  110. [txs opts before-editor-cursor]
  111. (let [txs (remove-nil-from-transaction txs)
  112. txs (map (fn [m] (if (map? m)
  113. (dissoc m
  114. :block/children :block/meta :block/top? :block/bottom? :block/anchor
  115. :block/title :block/body :block/level :block/container :db/other-tx
  116. :block/additional-properties)
  117. m)) txs)
  118. txs (-> (update-block-refs txs opts)
  119. (replace-ref-with-content opts)
  120. (distinct))]
  121. (when (and (seq txs)
  122. (not (:skip-transact? opts))
  123. (not (contains? (:file/unlinked-dirs @state/state)
  124. (config/get-repo-dir (state/get-current-repo)))))
  125. ;; (prn "[DEBUG] Outliner transact:")
  126. ;; (frontend.util/pprint {:txs txs :opts opts})
  127. (try
  128. (let [repo (get opts :repo (state/get-current-repo))
  129. conn (conn/get-db repo false)
  130. rs (d/transact! conn txs (assoc opts :outliner/transact? true))
  131. tx-id (get-tx-id rs)]
  132. (swap! state/state assoc-in [:history/tx->editor-cursor tx-id] before-editor-cursor)
  133. ;; update the current edit block to include full information
  134. (when-let [block (state/get-edit-block)]
  135. (when (and (:block/uuid block) (not (:db/id block)))
  136. (state/set-state! :editor/block (db/pull [:block/uuid (:block/uuid block)]))))
  137. (when true ; TODO: add debug flag
  138. (let [eids (distinct (mapv first (:tx-data rs)))
  139. left&parent-list (->>
  140. (d/q '[:find ?e ?l ?p
  141. :in $ [?e ...]
  142. :where
  143. [?e :block/left ?l]
  144. [?e :block/parent ?p]] @conn eids)
  145. (vec)
  146. (map next))]
  147. (assert (= (count left&parent-list) (count (distinct left&parent-list))) eids)))
  148. rs)
  149. (catch :default e
  150. (log/error :exception e)
  151. (throw e)))))))