pipeline.cljs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. (ns frontend.worker.pipeline
  2. "Pipeline work after transaction"
  3. (:require [datascript.core :as d]
  4. [frontend.worker.db.fix :as db-fix]
  5. [frontend.worker.file :as file]
  6. [frontend.worker.react :as worker-react]
  7. [frontend.worker.util :as worker-util]
  8. [logseq.db :as ldb]
  9. [logseq.db.frontend.validate :as db-validate]
  10. [logseq.db.sqlite.util :as sqlite-util]
  11. [logseq.outliner.datascript-report :as ds-report]
  12. [logseq.outliner.pipeline :as outliner-pipeline]
  13. [logseq.db.frontend.property :as db-property]
  14. [logseq.outliner.core :as outliner-core]))
  15. (defn- path-refs-need-recalculated?
  16. [tx-meta]
  17. (let [outliner-op (:outliner-op tx-meta)]
  18. (not (or
  19. (contains? #{:collapse-expand-blocks :delete-blocks} outliner-op)
  20. (:undo? tx-meta) (:redo? tx-meta)))))
  21. (defn compute-block-path-refs-tx
  22. [{:keys [tx-meta] :as tx-report} blocks]
  23. (when (or (and (:outliner-op tx-meta) (path-refs-need-recalculated? tx-meta))
  24. (:from-disk? tx-meta)
  25. (:new-graph? tx-meta))
  26. (outliner-pipeline/compute-block-path-refs-tx tx-report blocks)))
  27. (defn- delete-property-parent-block-if-empty
  28. [tx-report deleted-block-uuids]
  29. (let [after-db (:db-after tx-report)
  30. empty-property-parents (->> (keep (fn [child-id]
  31. (let [e (d/entity (:db-before tx-report) [:block/uuid child-id])]
  32. (when (get (:block/parent e) :logseq.property/created-from-property)
  33. (let [parent-now (d/entity after-db (:db/id (:block/parent e)))]
  34. (when (empty? (:block/_parent parent-now))
  35. parent-now))))) deleted-block-uuids)
  36. distinct)]
  37. (when (seq empty-property-parents)
  38. (->>
  39. (mapcat (fn [b]
  40. (let [created-from-block (get b :logseq.property/created-from-block)
  41. created-from-property (get b :logseq.property/created-from-property)
  42. created-block (d/entity after-db (:db/id created-from-block))
  43. pair-e (db-property/get-pair-e created-from-block (:db/ident created-from-property))
  44. tx-id (get-in tx-report [:tempids :db/current-tx])]
  45. (when (and created-block created-from-property)
  46. [[:db/retractEntity (:db/id b)]
  47. (when pair-e
  48. (outliner-core/block-with-updated-at
  49. {:db/id (:db/id pair-e)
  50. :block/tx-id tx-id}))
  51. (when pair-e
  52. (outliner-core/block-with-updated-at
  53. {:db/id (:db/id created-block)
  54. :block/tx-id tx-id}))])))
  55. empty-property-parents)
  56. (remove nil?)))))
  57. (defn fix-db!
  58. [conn {:keys [db-before db-after tx-data] :as tx-report} context]
  59. (let [changed-pages (->> (filter (fn [d] (contains? #{:block/left :block/parent} (:a d))) tx-data)
  60. (map :e)
  61. distinct
  62. (map (fn [id]
  63. (-> (or (d/entity db-after id)
  64. (d/entity db-before id))
  65. :block/page
  66. :db/id)))
  67. (remove nil?)
  68. (distinct))]
  69. (doseq [changed-page-id changed-pages]
  70. (db-fix/fix-page-if-broken! conn changed-page-id {:tx-report tx-report
  71. :context context}))))
  72. (defn validate-and-fix-db!
  73. [repo conn tx-report context]
  74. (when (and (:dev? context) (not (:importing? context)) (sqlite-util/db-based-graph? repo))
  75. (let [valid? (db-validate/validate-tx-report! tx-report (:validate-db-options context))]
  76. (when (and (get-in context [:validate-db-options :fail-invalid?]) (not valid?))
  77. (worker-util/post-message :notification
  78. [["Invalid DB!"] :error]))))
  79. (when (or (:dev? context) (exists? js/process))
  80. (fix-db! conn tx-report context)))
  81. (defn invoke-hooks
  82. [repo conn {:keys [tx-meta] :as tx-report} context]
  83. (when-not (:pipeline-replace? tx-meta)
  84. (let [{:keys [from-disk? new-graph?]} tx-meta]
  85. (cond
  86. (or from-disk? new-graph?)
  87. (let [{:keys [blocks]} (ds-report/get-blocks-and-pages tx-report)
  88. path-refs (distinct (compute-block-path-refs-tx tx-report blocks))
  89. tx-report' (or
  90. (when (seq path-refs)
  91. (ldb/transact! conn path-refs {:pipeline-replace? true}))
  92. (do
  93. (when-not (exists? js/process) (d/store @conn))
  94. tx-report))
  95. full-tx-data (concat (:tx-data tx-report) (:tx-data tx-report'))
  96. final-tx-report (assoc tx-report'
  97. :tx-meta (:tx-meta tx-report)
  98. :tx-data full-tx-data
  99. :db-before (:db-before tx-report))]
  100. {:tx-report final-tx-report})
  101. :else
  102. (let [{:keys [pages blocks]} (ds-report/get-blocks-and-pages tx-report)
  103. _ (when (sqlite-util/local-file-based-graph? repo)
  104. (let [page-ids (distinct (map :db/id pages))]
  105. (doseq [page-id page-ids]
  106. (when (d/entity @conn page-id)
  107. (file/sync-to-file repo page-id tx-meta)))))
  108. deleted-block-uuids (set (outliner-pipeline/filter-deleted-blocks (:tx-data tx-report)))
  109. replace-tx (concat
  110. ;; block path refs
  111. (set (compute-block-path-refs-tx tx-report blocks))
  112. ;; delete empty property parent block
  113. (when (seq deleted-block-uuids)
  114. (delete-property-parent-block-if-empty tx-report deleted-block-uuids))
  115. ;; update block/tx-id
  116. (let [updated-blocks (remove (fn [b] (contains? (set deleted-block-uuids) (:block/uuid b)))
  117. (concat pages blocks))
  118. tx-id (get-in tx-report [:tempids :db/current-tx])]
  119. (keep (fn [b]
  120. (when-let [db-id (:db/id b)]
  121. (when-not (:property/pair-property b)
  122. {:db/id db-id
  123. :block/tx-id tx-id}))) updated-blocks)))
  124. tx-report' (or
  125. (when (seq replace-tx)
  126. ;; TODO: remove this since transact! is really slow
  127. (ldb/transact! conn replace-tx {:pipeline-replace? true}))
  128. (do
  129. (when-not (exists? js/process) (d/store @conn))
  130. tx-report))
  131. fix-tx-data (validate-and-fix-db! repo conn tx-report context)
  132. full-tx-data (concat (:tx-data tx-report)
  133. fix-tx-data
  134. (:tx-data tx-report'))
  135. final-tx-report (assoc tx-report' :tx-data full-tx-data)
  136. affected-query-keys (when-not (:importing? context)
  137. (worker-react/get-affected-queries-keys final-tx-report))]
  138. {:tx-report final-tx-report
  139. :affected-keys affected-query-keys
  140. :deleted-block-uuids deleted-block-uuids
  141. :pages pages
  142. :blocks blocks})))))