/
pipeline.cljs
119 lines (111 loc) · 6.58 KB
/
pipeline.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
(ns frontend.modules.outliner.pipeline
(:require [frontend.modules.datascript-report.core :as ds-report]
[frontend.modules.outliner.file :as file]
[frontend.state :as state]
[frontend.util :as util]
[frontend.db.model :as db-model]
[frontend.db.react :as react]
[frontend.db :as db]
[clojure.set :as set]
[datascript.core :as d]))
(defn updated-page-hook
[tx-report page]
(when-not (get-in tx-report [:tx-meta :created-from-journal-template?])
(file/sync-to-file page (:outliner-op (:tx-meta tx-report)))))
;; TODO: it'll be great if we can calculate the :block/path-refs before any
;; outliner transaction, this way we can group together the real outliner tx
;; and the new path-refs changes, which makes both undo/redo and
;; react-query/refresh! easier.
;; TODO: also need to consider whiteboard transactions
;; Steps:
;; 1. For each changed block, new-refs = its page + :block/refs + parents :block/refs
;; 2. Its children' block/path-refs might need to be updated too.
(defn compute-block-path-refs
[{:keys [tx-meta db-before]} blocks]
(let [repo (state/get-current-repo)
blocks (remove :block/name blocks)]
(when (:outliner-op tx-meta)
(when (react/path-refs-need-recalculated? tx-meta)
(let [*computed-ids (atom #{})]
(mapcat (fn [block]
(when (and (not (@*computed-ids (:block/uuid block))) ; not computed yet
(not (:block/name block)))
(let [parents (db-model/get-block-parents repo (:block/uuid block))
parents-refs (->> (mapcat :block/path-refs parents)
(map :db/id))
old-refs (set (map :db/id (:block/path-refs (d/entity db-before (:db/id block)))))
new-refs (set (util/concat-without-nil
[(:db/id (:block/page block))]
(map :db/id (:block/refs block))
parents-refs))
;; Usually has changed as new-refs has page id while old-refs doesn't
refs-changed? (not= old-refs new-refs)
children (db-model/get-block-children-ids repo (:block/uuid block))
;; Builds map of children ids to their parent id and :block/refs ids
children-maps (into {}
(map (fn [id]
(let [entity (db/entity [:block/uuid id])]
[(:db/id entity)
{:parent-id (get-in entity [:block/parent :db/id])
:block-ref-ids (map :db/id (:block/refs entity))}]))
children))
children-refs (map (fn [[id {:keys [block-ref-ids] :as child-map}]]
{:db/id id
;; Recalculate :block/path-refs as db contains stale data for this attribute
:block/path-refs
(set/union
;; Refs from top-level parent
new-refs
;; Refs from current block
block-ref-ids
;; Refs from parents in between top-level
;; parent and current block
(loop [parent-refs #{}
parent-id (:parent-id child-map)]
(if-let [parent (children-maps parent-id)]
(recur (into parent-refs (:block-ref-ids parent))
(:parent-id parent))
;; exits when top-level parent is reached
parent-refs)))})
children-maps)]
(swap! *computed-ids set/union (set (cons (:block/uuid block) children)))
(util/concat-without-nil
[(when (and (seq new-refs)
refs-changed?)
{:db/id (:db/id block)
:block/path-refs new-refs})]
children-refs))))
blocks))))))
(defn invoke-hooks
[tx-report]
(let [tx-meta (:tx-meta tx-report)]
(when (and (not (:from-disk? tx-meta))
(not (:new-graph? tx-meta))
(not (:replace? tx-meta)))
(let [{:keys [pages blocks]} (ds-report/get-blocks-and-pages tx-report)
repo (state/get-current-repo)
refs-tx (util/profile
"Compute path refs: "
(set (compute-block-path-refs tx-report blocks)))
truncate-refs-tx (map (fn [m] [:db/retract (:db/id m) :block/path-refs]) refs-tx)
tx (util/concat-without-nil truncate-refs-tx refs-tx)
tx-report' (if (seq tx)
(let [refs-tx-data' (:tx-data (db/transact! repo tx {:outliner/transact? true
:replace? true}))]
;; merge
(assoc tx-report :tx-data (concat (:tx-data tx-report) refs-tx-data')))
tx-report)
importing? (:graph/importing @state/state)]
(when-not importing?
(react/refresh! repo tx-report'))
(when-not (:delete-files? tx-meta)
(doseq [p (seq pages)]
(updated-page-hook tx-report p)))
(when (and state/lsp-enabled?
(seq blocks)
(not importing?)
(<= (count blocks) 1000))
(state/pub-event! [:plugin/hook-db-tx
{:blocks blocks
:tx-data (:tx-data tx-report)
:tx-meta (:tx-meta tx-report)}]))))))