model.cljs 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658
  1. (ns frontend.db.model
  2. "Core db functions."
  3. ;; TODO: Remove this config once how repos are passed to this ns are standardized
  4. {:clj-kondo/config {:linters {:unused-binding {:level :off}}}}
  5. (:require [clojure.set :as set]
  6. [clojure.string :as string]
  7. [clojure.walk :as walk]
  8. [datascript.core :as d]
  9. [frontend.config :as config]
  10. [frontend.date :as date]
  11. [logseq.db.schema :as db-schema]
  12. [frontend.db.conn :as conn]
  13. [frontend.db.react :as react]
  14. [frontend.db.utils :as db-utils]
  15. [frontend.state :as state]
  16. [frontend.util :as util :refer [react]]
  17. [logseq.graph-parser.util :as gp-util]
  18. [logseq.db.rules :refer [rules]]
  19. [logseq.db.default :as default-db]
  20. [frontend.util.drawer :as drawer]))
  21. ;; lazy loading
  22. (def initial-blocks-length 50)
  23. (def step-loading-blocks 25)
  24. ;; TODO: extract to specific models and move data transform logic to the
  25. ;; corresponding handlers.
  26. ;; Use it as an input argument for datalog queries
  27. (def block-attrs
  28. '[:db/id
  29. :block/uuid
  30. :block/parent
  31. :block/left
  32. :block/collapsed?
  33. :block/format
  34. :block/refs
  35. :block/_refs
  36. :block/path-refs
  37. :block/tags
  38. :block/content
  39. :block/marker
  40. :block/priority
  41. :block/properties
  42. :block/pre-block?
  43. :block/scheduled
  44. :block/deadline
  45. :block/repeated?
  46. :block/created-at
  47. :block/updated-at
  48. :block/file
  49. :block/heading-level
  50. {:block/page [:db/id :block/name :block/original-name :block/journal-day]}
  51. {:block/_parent ...}])
  52. (defn pull-block
  53. [id]
  54. (let [repo (state/get-current-repo)]
  55. (when (conn/get-db repo)
  56. (->
  57. (react/q repo [:frontend.db.react/block id] {}
  58. '[:find [(pull ?block ?block-attrs) ...]
  59. :in $ ?id ?block-attrs
  60. :where
  61. [?block :block/uuid ?id]]
  62. id
  63. block-attrs)
  64. react
  65. first))))
  66. (defn get-original-name
  67. [page-entity]
  68. (or (:block/original-name page-entity)
  69. (:block/name page-entity)))
  70. (defn get-tag-pages
  71. [repo tag-name]
  72. (when tag-name
  73. (d/q '[:find ?original-name ?name
  74. :in $ ?tag
  75. :where
  76. [?e :block/name ?tag]
  77. [?page :block/tags ?e]
  78. [?page :block/original-name ?original-name]
  79. [?page :block/name ?name]]
  80. (conn/get-db repo)
  81. (util/page-name-sanity-lc tag-name))))
  82. (defn get-all-tagged-pages
  83. [repo]
  84. (d/q '[:find ?page-name ?tag
  85. :where
  86. [?page :block/tags ?e]
  87. [?e :block/name ?tag]
  88. [?page :block/name ?page-name]]
  89. (conn/get-db repo)))
  90. (defn get-all-namespace-relation
  91. [repo]
  92. (d/q '[:find ?page-name ?parent
  93. :where
  94. [?page :block/name ?page-name]
  95. [?page :block/namespace ?e]
  96. [?e :block/name ?parent]]
  97. (conn/get-db repo)))
  98. (defn get-pages
  99. [repo]
  100. (->> (d/q
  101. '[:find ?page-original-name
  102. :where
  103. [?page :block/name ?page-name]
  104. [(get-else $ ?page :block/original-name ?page-name) ?page-original-name]]
  105. (conn/get-db repo))
  106. (map first)))
  107. (defn get-all-pages
  108. [repo]
  109. (d/q
  110. '[:find [(pull ?page [*]) ...]
  111. :where
  112. [?page :block/name]]
  113. (conn/get-db repo)))
  114. (defn get-page-alias
  115. [repo page-name]
  116. (when-let [db (and repo (conn/get-db repo))]
  117. (some->> (d/q '[:find ?alias
  118. :in $ ?page-name
  119. :where
  120. [?page :block/name ?page-name]
  121. [?page :block/alias ?alias]]
  122. db
  123. (util/page-name-sanity-lc page-name))
  124. db-utils/seq-flatten
  125. distinct)))
  126. (defn get-alias-source-page
  127. [repo alias]
  128. (when-let [db (and repo (conn/get-db repo))]
  129. (let [alias (util/page-name-sanity-lc alias)
  130. pages (->>
  131. (d/q '[:find (pull ?p [*])
  132. :in $ ?alias
  133. :where
  134. [?a :block/name ?alias]
  135. [?p :block/alias ?a]]
  136. db
  137. alias)
  138. (db-utils/seq-flatten))]
  139. (when (seq pages)
  140. (some (fn [page]
  141. (let [aliases (->> (get-in page [:block/properties :alias])
  142. (map util/page-name-sanity-lc)
  143. set)]
  144. (when (contains? aliases alias)
  145. page)))
  146. pages)))))
  147. (defn get-files
  148. [repo]
  149. (when-let [db (conn/get-db repo)]
  150. (->> (d/q
  151. '[:find ?path
  152. ;; ?modified-at
  153. :where
  154. [?file :file/path ?path]
  155. ;; [?file :file/last-modified-at ?modified-at]
  156. ]
  157. db)
  158. (seq)
  159. ;; (sort-by last)
  160. (reverse))))
  161. (defn get-files-v2
  162. [repo]
  163. (when-let [db (conn/get-db repo)]
  164. (->> (d/q
  165. '[:find ?file ?path
  166. ;; ?modified-at
  167. :where
  168. [?file :file/path ?path]
  169. ;; [?file :file/last-modified-at ?modified-at]
  170. ]
  171. db)
  172. (seq)
  173. ;; (sort-by last)
  174. (reverse))))
  175. (defn get-files-blocks
  176. [repo-url paths]
  177. (let [paths (set paths)
  178. pred (fn [_db e]
  179. (contains? paths e))]
  180. (-> (d/q '[:find ?block
  181. :in $ ?pred
  182. :where
  183. [?file :file/path ?path]
  184. [(?pred $ ?path)]
  185. [?p :block/file ?file]
  186. [?block :block/page ?p]]
  187. (conn/get-db repo-url) pred)
  188. db-utils/seq-flatten)))
  189. (defn get-file-blocks
  190. [repo-url path]
  191. (-> (d/q '[:find ?block
  192. :in $ ?path
  193. :where
  194. [?file :file/path ?path]
  195. [?p :block/file ?file]
  196. [?block :block/page ?p]]
  197. (conn/get-db repo-url) path)
  198. db-utils/seq-flatten))
  199. (defn set-file-last-modified-at!
  200. [repo path last-modified-at]
  201. (when (and repo path last-modified-at)
  202. (when-let [conn (conn/get-db repo false)]
  203. (d/transact! conn
  204. [{:file/path path
  205. :file/last-modified-at last-modified-at}]
  206. {:skip-refresh? true}))))
  207. (defn get-file-last-modified-at
  208. [repo path]
  209. (when (and repo path)
  210. (when-let [db (conn/get-db repo)]
  211. (-> (d/entity db [:file/path path])
  212. :file/last-modified-at))))
  213. (defn file-exists?
  214. [repo path]
  215. (when (and repo path)
  216. (when-let [db (conn/get-db repo)]
  217. (d/entity db [:file/path path]))))
  218. (defn get-files-full
  219. [repo]
  220. (when-let [db (conn/get-db repo)]
  221. (->>
  222. (d/q
  223. '[:find (pull ?file [*])
  224. :where
  225. [?file :file/path]]
  226. db)
  227. (flatten))))
  228. (defn get-file
  229. ([path]
  230. (get-file (state/get-current-repo) path))
  231. ([repo path]
  232. (when (and repo path)
  233. (when-let [db (conn/get-db repo)]
  234. (:file/content (d/entity db [:file/path path]))))))
  235. (defn get-custom-css
  236. []
  237. (when-let [repo (state/get-current-repo)]
  238. (get-file (config/get-file-path repo "logseq/custom.css"))))
  239. (defn get-block-by-uuid
  240. [id]
  241. (db-utils/entity [:block/uuid (if (uuid? id) id (uuid id))]))
  242. (defn query-block-by-uuid
  243. [id]
  244. (db-utils/pull [:block/uuid (if (uuid? id) id (uuid id))]))
  245. (defn get-page-format
  246. [page-name]
  247. (or
  248. (let [page (db-utils/entity [:block/name (util/safe-page-name-sanity-lc page-name)])]
  249. (or
  250. (:block/format page)
  251. (when-let [file (:block/file page)]
  252. (when-let [path (:file/path (db-utils/entity (:db/id file)))]
  253. (gp-util/get-format path)))))
  254. (state/get-preferred-format)
  255. :markdown))
  256. (defn page-alias-set
  257. [repo-url page]
  258. (when-let [page-id (:db/id (db-utils/entity repo-url [:block/name (util/safe-page-name-sanity-lc page)]))]
  259. (->>
  260. (d/q '[:find ?e
  261. :in $ ?page-name %
  262. :where
  263. [?page :block/name ?page-name]
  264. (alias ?page ?e)]
  265. (conn/get-db repo-url)
  266. (util/safe-page-name-sanity-lc page)
  267. '[[(alias ?e2 ?e1)
  268. [?e2 :block/alias ?e1]]
  269. [(alias ?e2 ?e1)
  270. [?e1 :block/alias ?e2]]
  271. [(alias ?e1 ?e3)
  272. [?e1 :block/alias ?e2]
  273. [?e2 :block/alias ?e3]]
  274. [(alias ?e3 ?e1)
  275. [?e1 :block/alias ?e2]
  276. [?e2 :block/alias ?e3]]])
  277. db-utils/seq-flatten
  278. (set)
  279. (set/union #{page-id}))))
  280. (defn get-entities-by-ids
  281. ([ids]
  282. (get-entities-by-ids (state/get-current-repo) ids))
  283. ([repo ids]
  284. (when repo
  285. (db-utils/pull-many repo '[*] ids))))
  286. (defn get-page-names-by-ids
  287. ([ids]
  288. (get-page-names-by-ids (state/get-current-repo) ids))
  289. ([repo ids]
  290. (when repo
  291. (->> (db-utils/pull-many repo '[:block/name] ids)
  292. (map :block/name)))))
  293. (defn get-page-alias-names
  294. [repo page-name]
  295. (let [alias-ids (page-alias-set repo page-name)]
  296. (when (seq alias-ids)
  297. (let [names (->> (get-page-names-by-ids repo alias-ids)
  298. distinct
  299. (remove #(= (util/page-name-sanity-lc %) (util/page-name-sanity-lc page-name))))
  300. lookup-refs (map (fn [name]
  301. [:block/name (util/page-name-sanity-lc name)]) names)]
  302. (->> (db-utils/pull-many repo '[:block/name :block/original-name] lookup-refs)
  303. (map (fn [m]
  304. (or (:block/original-name m) (:block/name m)))))))))
  305. (defn with-pages
  306. [blocks]
  307. (let [pages-ids (->> (map (comp :db/id :block/page) blocks)
  308. (remove nil?))
  309. pages (when (seq pages-ids)
  310. (db-utils/pull-many '[:db/id :block/name :block/original-name :block/journal-day] pages-ids))
  311. pages-map (reduce (fn [acc p] (assoc acc (:db/id p) p)) {} pages)
  312. blocks (map
  313. (fn [block]
  314. (assoc block :block/page
  315. (get pages-map (:db/id (:block/page block)))))
  316. blocks)]
  317. blocks))
  318. (defn get-page-properties
  319. [page]
  320. (when-let [page (db-utils/entity [:block/name (util/safe-page-name-sanity-lc page)])]
  321. (:block/properties page)))
  322. ;; FIXME: alert
  323. (defn sort-by-left
  324. ([blocks parent]
  325. (sort-by-left blocks parent {:check? true}))
  326. ([blocks parent {:keys [check?]}]
  327. (when check?
  328. (when (not= (count blocks) (count (set (map :block/left blocks))))
  329. (let [duplicates (->> (map (comp :db/id :block/left) blocks)
  330. frequencies
  331. (filter (fn [[_k v]] (> v 1)))
  332. (map (fn [[k _v]]
  333. (let [left (db-utils/pull k)]
  334. {:left left
  335. :duplicates (->>
  336. (filter (fn [block]
  337. (= k (:db/id (:block/left block))))
  338. blocks)
  339. (map #(select-keys % [:db/id :block/level :block/content :block/file])))}))))]
  340. #_(util/pprint duplicates)))
  341. (assert (= (count blocks) (count (set (map :block/left blocks)))) "Each block should have a different left node"))
  342. (let [left->blocks (reduce (fn [acc b] (assoc acc (:db/id (:block/left b)) b)) {} blocks)]
  343. (loop [block parent
  344. result []]
  345. (if-let [next (get left->blocks (:db/id block))]
  346. (recur next (conj result next))
  347. (vec result))))))
  348. (defn sort-by-left-recursive
  349. [form]
  350. (walk/postwalk (fn [f]
  351. (if (and (map? f)
  352. (:block/_parent f))
  353. (let [children (:block/_parent f)]
  354. (-> f
  355. (dissoc :block/_parent)
  356. (assoc :block/children (sort-by-left children f))))
  357. f))
  358. form))
  359. (defn get-sorted-page-block-ids
  360. [page-id]
  361. (let [root (db-utils/entity page-id)]
  362. (loop [result []
  363. children (sort-by-left (:block/_parent root) root)]
  364. (if (seq children)
  365. (let [child (first children)]
  366. (recur (conj result (:db/id child))
  367. (concat
  368. (sort-by-left (:block/_parent child) child)
  369. (rest children))))
  370. result))))
  371. (defn sort-page-random-blocks
  372. "Blocks could be non consecutive."
  373. [blocks]
  374. (assert (every? #(= (:block/page %) (:block/page (first blocks))) blocks) "Blocks must to be in a same page.")
  375. (let [page-id (:db/id (:block/page (first blocks)))
  376. ;; TODO: there's no need to sort all the blocks
  377. sorted-ids (get-sorted-page-block-ids page-id)
  378. blocks-map (zipmap (map :db/id blocks) blocks)]
  379. (keep blocks-map sorted-ids)))
  380. (defn has-children?
  381. ([block-id]
  382. (has-children? (conn/get-db) block-id))
  383. ([db block-id]
  384. (some? (:block/_parent (d/entity db [:block/uuid block-id])))))
  385. (defn- collapsed-and-has-children?
  386. [db block]
  387. (and (:block/collapsed? block) (has-children? db (:block/uuid block))))
  388. (defn get-by-parent-&-left
  389. [db parent-id left-id]
  390. (when (and parent-id left-id)
  391. (let [lefts (:block/_left (d/entity db left-id))]
  392. (some (fn [node] (when (and (= parent-id (:db/id (:block/parent node)))
  393. (not= parent-id (:db/id node)))
  394. node)) lefts))))
  395. (defn- get-next-outdented-block
  396. "Get the next outdented block of the block that has the `id`.
  397. e.g.
  398. - a
  399. - b
  400. - c
  401. - d
  402. The next outdented block of `c` is `d`."
  403. [db id]
  404. (when-let [block (d/entity db id)]
  405. (let [parent (:block/parent block)]
  406. (if-let [parent-sibling (get-by-parent-&-left db
  407. (:db/id (:block/parent parent))
  408. (:db/id parent))]
  409. parent-sibling
  410. (get-next-outdented-block db (:db/id parent))))))
  411. (defn get-block-parent
  412. ([block-id]
  413. (get-block-parent (state/get-current-repo) block-id))
  414. ([repo block-id]
  415. (when-let [db (conn/get-db repo)]
  416. (when-let [block (d/entity db [:block/uuid block-id])]
  417. (:block/parent block)))))
  418. (defn top-block?
  419. [block]
  420. (= (:db/id (:block/parent block))
  421. (:db/id (:block/page block))))
  422. ;; non recursive query
  423. (defn get-block-parents
  424. ([repo block-id]
  425. (get-block-parents repo block-id 100))
  426. ([repo block-id depth]
  427. (loop [block-id block-id
  428. parents (list)
  429. d 1]
  430. (if (> d depth)
  431. parents
  432. (if-let [parent (get-block-parent repo block-id)]
  433. (recur (:block/uuid parent) (conj parents parent) (inc d))
  434. parents)))))
  435. (comment
  436. (defn get-immediate-children-v2
  437. [repo block-id]
  438. (d/pull (conn/get-db repo)
  439. '[:block/_parent]
  440. [:block/uuid block-id])))
  441. ;; Use built-in recursive
  442. (defn get-block-parents-v2
  443. [repo block-id]
  444. (d/pull (conn/get-db repo)
  445. '[:db/id :block/collapsed? :block/properties {:block/parent ...}]
  446. [:block/uuid block-id]))
  447. (defn get-next-open-block
  448. ([db block]
  449. (get-next-open-block db block nil))
  450. ([db block scoped-block-id]
  451. (let [block-id (:db/id block)
  452. block-parent-id (:db/id (:block/parent block))
  453. next-block (or
  454. (if (and (collapsed-and-has-children? db block)
  455. (not= block-id scoped-block-id)) ; skips children
  456. ;; Sibling
  457. (get-by-parent-&-left db block-parent-id block-id)
  458. (or
  459. ;; Child
  460. (get-by-parent-&-left db block-id block-id)
  461. ;; Sibling
  462. (get-by-parent-&-left db block-parent-id block-id)))
  463. ;; Next outdented block
  464. (get-next-outdented-block db block-id))]
  465. (if (and scoped-block-id next-block)
  466. (let [parents (->> (get-block-parents (state/get-current-repo) (:block/uuid next-block))
  467. (map :db/id)
  468. (set))]
  469. (when (contains? parents scoped-block-id)
  470. next-block))
  471. next-block))))
  472. (defn get-paginated-blocks-no-cache
  473. "Result should be sorted."
  474. [db start-id {:keys [limit include-start? scoped-block-id end-id]}]
  475. (when-let [start (d/entity db start-id)]
  476. (let [scoped-block-parents (when scoped-block-id
  477. (let [block (d/entity db scoped-block-id)]
  478. (->> (get-block-parents (state/get-current-repo) (:block/uuid block))
  479. (map :db/id)
  480. (set))))
  481. result (loop [block start
  482. result []]
  483. (if (and limit (>= (count result) limit))
  484. result
  485. (let [next-block (get-next-open-block db block scoped-block-id)]
  486. (if next-block
  487. (cond
  488. (and (seq scoped-block-parents)
  489. (contains? scoped-block-parents (:db/id (:block/parent next-block))))
  490. result
  491. (and end-id (= end-id (:db/id next-block)))
  492. (conj result next-block)
  493. :else
  494. (recur next-block (conj result next-block)))
  495. result))))]
  496. (if include-start?
  497. (cons start result)
  498. result))))
  499. (defn get-block-last-direct-child
  500. "Notice: if `not-collapsed?` is true, will skip searching for any collapsed block."
  501. ([db db-id]
  502. (get-block-last-direct-child db db-id true))
  503. ([db db-id not-collapsed?]
  504. (when-let [block (d/entity db db-id)]
  505. (when (if not-collapsed?
  506. (not (collapsed-and-has-children? db block))
  507. true)
  508. (let [children (:block/_parent block)
  509. all-left (set (concat (map (comp :db/id :block/left) children) [db-id]))
  510. all-ids (set (map :db/id children))]
  511. (first (set/difference all-ids all-left)))))))
  512. (defn get-block-last-child
  513. [db db-id]
  514. (let [last-child (get-block-last-direct-child db db-id)]
  515. (loop [prev last-child
  516. last-child last-child]
  517. (if last-child
  518. (recur last-child (get-block-last-direct-child db last-child))
  519. prev))))
  520. (defn get-prev-open-block
  521. [db id]
  522. (let [block (d/entity db id)
  523. left (:block/left block)
  524. left-id (:db/id left)]
  525. (if (= (:db/id left) (:db/id (:block/parent block)))
  526. left-id
  527. (if (util/collapsed? left)
  528. left-id
  529. (or (get-block-last-child db (:db/id left)) left-id)))))
  530. (defn recursive-child?
  531. [repo child-id parent-id]
  532. (let [*last-node (atom nil)]
  533. (loop [node (db-utils/entity repo child-id)]
  534. (when-not (= @*last-node node)
  535. (reset! *last-node node)
  536. (if node
  537. (let [parent (:block/parent node)]
  538. (if (= (:db/id parent) parent-id)
  539. true
  540. (recur parent)))
  541. false)))))
  542. (defn get-prev-sibling
  543. [db id]
  544. (when-let [e (d/entity db id)]
  545. (let [left (:block/left e)]
  546. (when (not= (:db/id left) (:db/id (:block/parent e)))
  547. left))))
  548. (defn get-right-sibling
  549. [db db-id]
  550. (when-let [block (d/entity db db-id)]
  551. (get-by-parent-&-left db
  552. (:db/id (:block/parent block))
  553. db-id)))
  554. (defn last-child-block?
  555. "The child block could be collapsed."
  556. [db parent-id child-id]
  557. (when-let [child (d/entity db child-id)]
  558. (cond
  559. (= parent-id child-id)
  560. true
  561. (get-right-sibling db child-id)
  562. false
  563. :else
  564. (last-child-block? db parent-id (:db/id (:block/parent child))))))
  565. (defn- consecutive-block?
  566. [block-1 block-2]
  567. (let [db (conn/get-db)
  568. aux-fn (fn [block-1 block-2]
  569. (and (= (:block/page block-1) (:block/page block-2))
  570. (or
  571. ;; sibling or child
  572. (= (:db/id (:block/left block-2)) (:db/id block-1))
  573. (when-let [prev-sibling (get-prev-sibling db (:db/id block-2))]
  574. (last-child-block? db (:db/id prev-sibling) (:db/id block-1))))))]
  575. (or (aux-fn block-1 block-2) (aux-fn block-2 block-1))))
  576. (defn get-non-consecutive-blocks
  577. [blocks]
  578. (vec
  579. (keep-indexed
  580. (fn [i _block]
  581. (when (< (inc i) (count blocks))
  582. (when-not (consecutive-block? (nth blocks i)
  583. (nth blocks (inc i)))
  584. (nth blocks i))))
  585. blocks)))
  586. (defn- get-start-id-for-pagination-query
  587. [repo-url current-db {:keys [db-before tx-meta] :as tx-report}
  588. result outliner-op page-id block-id tx-block-ids]
  589. (let [db-before (or db-before current-db)
  590. cached-ids (map :db/id @result)
  591. cached-ids-set (set (conj cached-ids page-id))
  592. first-changed-id (cond
  593. (= (:real-outliner-op tx-meta) :indent-outdent)
  594. (if (state/logical-outdenting?)
  595. (first (:move-blocks tx-meta))
  596. (last (:move-blocks tx-meta)))
  597. (= outliner-op :move-blocks)
  598. (let [{:keys [move-blocks target from-page to-page]} tx-meta]
  599. (cond
  600. (= page-id target) ; move to the first block
  601. nil
  602. (and from-page to-page (not= from-page to-page))
  603. (if (= page-id from-page)
  604. (first move-blocks)
  605. target)
  606. :else
  607. ;; same page, get the most top block before dragging
  608. (let [match-ids (set (conj move-blocks target))]
  609. (loop [[id & others] cached-ids]
  610. (if id
  611. (if (contains? match-ids id)
  612. id
  613. (when (seq others)
  614. (recur others)))
  615. nil)))))
  616. :else
  617. (let [insert? (= :insert-blocks outliner-op)]
  618. (some #(when (and (or (and insert? (not (contains? cached-ids-set %)))
  619. true)
  620. (recursive-child? repo-url % block-id))
  621. %) tx-block-ids)))]
  622. (when first-changed-id
  623. (or (get-prev-open-block db-before first-changed-id)
  624. (get-prev-open-block current-db first-changed-id)))))
  625. (defn- build-paginated-blocks-from-cache
  626. "Notice: tx-report could be nil."
  627. [repo-url tx-report result outliner-op page-id block-id tx-block-ids scoped-block-id]
  628. (let [{:keys [tx-meta]} tx-report
  629. current-db (conn/get-db repo-url)]
  630. (cond
  631. (and (or (:undo? tx-meta) (:redo? tx-meta)) @result)
  632. (let [blocks-range (:pagination-blocks-range tx-meta)
  633. [start-block-id end-block-id] (:new blocks-range)]
  634. (get-paginated-blocks-no-cache current-db start-block-id
  635. {:end-id end-block-id
  636. :include-start? true
  637. :scoped-block-id scoped-block-id}))
  638. (contains? #{:save-block :delete-blocks} outliner-op)
  639. @result
  640. (contains? #{:insert-blocks :collapse-expand-blocks :move-blocks} outliner-op)
  641. (when-let [start-id (get-start-id-for-pagination-query
  642. repo-url current-db tx-report result outliner-op page-id block-id tx-block-ids)]
  643. (let [start-page? (:block/name (db-utils/entity start-id))]
  644. (when-not start-page?
  645. (let [previous-blocks (take-while (fn [b] (not= start-id (:db/id b))) @result)
  646. limit (-> (max (- initial-blocks-length (count previous-blocks))
  647. (count tx-block-ids))
  648. (+ 25))
  649. more (get-paginated-blocks-no-cache current-db start-id {:limit limit
  650. :include-start? true
  651. :scoped-block-id scoped-block-id})]
  652. (concat previous-blocks more)))))
  653. :else
  654. nil)))
  655. (defn get-paginated-blocks
  656. "Get paginated blocks for a page or a specific block.
  657. `scoped-block-id`: if specified, returns its children only."
  658. ([repo-url block-id]
  659. (get-paginated-blocks repo-url block-id {}))
  660. ([repo-url block-id {:keys [pull-keys start-block limit use-cache? scoped-block-id]
  661. :or {pull-keys '[* :block/_refs]
  662. limit initial-blocks-length
  663. use-cache? true
  664. scoped-block-id nil}}]
  665. (when block-id
  666. (assert (integer? block-id) (str "wrong block-id: " block-id))
  667. (let [entity (db-utils/entity repo-url block-id)
  668. page? (some? (:block/name entity))
  669. page-entity (if page? entity (:block/page entity))
  670. page-id (:db/id page-entity)
  671. bare-page-map {:db/id page-id
  672. :block/name (:block/name page-entity)
  673. :block/original-name (:block/original-name page-entity)
  674. :block/journal-day (:block/journal-day page-entity)}
  675. query-key (if page?
  676. :frontend.db.react/page-blocks
  677. :frontend.db.react/block-and-children)]
  678. (some->
  679. (react/q repo-url [query-key block-id]
  680. {:use-cache? use-cache?
  681. :query-fn (fn [db tx-report result]
  682. (let [tx-data (:tx-data tx-report)
  683. refs (some->> (filter #(= :block/refs (:a %)) tx-data)
  684. (map :v))
  685. tx-block-ids (distinct (-> (map :e tx-data)
  686. (concat refs)))
  687. [tx-id->block cached-id->block] (when (and tx-report result)
  688. (let [blocks (->> (db-utils/pull-many repo-url pull-keys tx-block-ids)
  689. (remove nil?))]
  690. [(zipmap (mapv :db/id blocks) blocks)
  691. (zipmap (mapv :db/id @result) @result)]))
  692. limit (if (and result @result)
  693. (max (+ (count @result) 5) limit)
  694. limit)
  695. outliner-op (get-in tx-report [:tx-meta :outliner-op])
  696. blocks (build-paginated-blocks-from-cache repo-url tx-report result outliner-op page-id block-id tx-block-ids scoped-block-id)
  697. blocks (or blocks
  698. (get-paginated-blocks-no-cache (conn/get-db repo-url) block-id {:limit limit
  699. :include-start? (not page?)
  700. :scoped-block-id scoped-block-id}))
  701. block-eids (map :db/id blocks)
  702. blocks (if (and (seq tx-id->block)
  703. (not (contains? #{:move-blocks} outliner-op)))
  704. (map (fn [id]
  705. (or (get tx-id->block id)
  706. (get cached-id->block id)
  707. (db-utils/pull repo-url pull-keys id))) block-eids)
  708. (db-utils/pull-many repo-url pull-keys block-eids))
  709. blocks (remove (fn [b] (nil? (:block/content b))) blocks)]
  710. (map (fn [b] (assoc b :block/page bare-page-map)) blocks)))}
  711. nil)
  712. react)))))
  713. (defn get-page-blocks-no-cache
  714. ([page]
  715. (get-page-blocks-no-cache (state/get-current-repo) page nil))
  716. ([repo-url page]
  717. (get-page-blocks-no-cache repo-url page nil))
  718. ([repo-url page {:keys [pull-keys]
  719. :or {pull-keys '[*]}}]
  720. (when page
  721. (let [page (util/page-name-sanity-lc page)
  722. page-id (:db/id (db-utils/entity repo-url [:block/name page]))
  723. db (conn/get-db repo-url)]
  724. (when page-id
  725. (let [datoms (d/datoms db :avet :block/page page-id)
  726. block-eids (mapv :e datoms)]
  727. (db-utils/pull-many repo-url pull-keys block-eids)))))))
  728. (defn get-page-blocks-count
  729. [repo page-id]
  730. (when-let [db (conn/get-db repo)]
  731. (count (d/datoms db :avet :block/page page-id))))
  732. (defn page-exists?
  733. "Whether a page exists."
  734. [page-name]
  735. (when page-name
  736. (db-utils/entity [:block/name (util/page-name-sanity-lc page-name)])))
  737. (defn page-empty?
  738. "Whether a page is empty. Does it has a non-page block?
  739. `page-id` could be either a string or a db/id."
  740. [repo page-id]
  741. (when-let [db (conn/get-db repo)]
  742. (let [page-id (if (string? page-id)
  743. [:block/name (util/safe-page-name-sanity-lc page-id)]
  744. page-id)
  745. page (d/entity db page-id)]
  746. (nil? (:block/_left page)))))
  747. (defn page-empty-or-dummy?
  748. [repo page-id]
  749. (or
  750. (page-empty? repo page-id)
  751. (when-let [db (conn/get-db repo)]
  752. (let [datoms (d/datoms db :avet :block/page page-id)]
  753. (and (= (count datoms) 1)
  754. (= "" (:block/content (db-utils/pull (:e (first datoms))))))))))
  755. (defn parents-collapsed?
  756. [repo block-id]
  757. (when-let [block (:block/parent (get-block-parents-v2 repo block-id))]
  758. (->> (tree-seq map? (fn [x] [(:block/parent x)]) block)
  759. (some util/collapsed?))))
  760. (defn get-block-page
  761. [repo block-id]
  762. (when-let [block (db-utils/entity repo [:block/uuid block-id])]
  763. (db-utils/entity repo (:db/id (:block/page block)))))
  764. (defn get-pages-by-name-partition
  765. [repo partition]
  766. (when-let [db (conn/get-db repo)]
  767. (when-not (string/blank? partition)
  768. (let [partition (util/page-name-sanity-lc (string/trim partition))
  769. ids (->> (d/datoms db :aevt :block/name)
  770. (filter (fn [datom]
  771. (let [page (:v datom)]
  772. (string/includes? page partition))))
  773. (map :e))]
  774. (when (seq ids)
  775. (db-utils/pull-many repo
  776. '[:db/id :block/name :block/original-name]
  777. ids))))))
  778. (defn get-block-children-ids
  779. [repo block-uuid]
  780. (when-let [db (conn/get-db repo)]
  781. (let [eid (:db/id (db-utils/entity repo [:block/uuid block-uuid]))]
  782. (->> (d/q
  783. '[:find ?id
  784. :in $ ?p %
  785. :where
  786. (child ?p ?c)
  787. [?c :block/uuid ?id]]
  788. db
  789. eid
  790. rules)
  791. (apply concat)))))
  792. (defn get-block-immediate-children
  793. "Doesn't include nested children."
  794. [repo block-uuid]
  795. (when-let [db (conn/get-db repo)]
  796. (-> (d/q
  797. '[:find [(pull ?b [*]) ...]
  798. :in $ ?parent-id
  799. :where
  800. [?parent :block/uuid ?parent-id]
  801. [?b :block/parent ?parent]]
  802. db
  803. block-uuid)
  804. (sort-by-left (db-utils/entity [:block/uuid block-uuid])))))
  805. (defn sub-block-direct-children
  806. "Doesn't include nested children."
  807. [repo block-uuid]
  808. (when-let [db (conn/get-db repo)]
  809. (-> (react/q repo [:frontend.db.react/block-direct-children block-uuid] {}
  810. '[:find [(pull ?b [*]) ...]
  811. :in $ ?parent-id
  812. :where
  813. [?parent :block/uuid ?parent-id]
  814. [?b :block/parent ?parent]]
  815. block-uuid)
  816. react
  817. (sort-by-left (db-utils/entity [:block/uuid block-uuid])))))
  818. (defn get-block-children
  819. "Including nested children."
  820. [repo block-uuid]
  821. (let [ids (get-block-children-ids repo block-uuid)
  822. ids (map (fn [id] [:block/uuid id]) ids)]
  823. (when (seq ids)
  824. (db-utils/pull-many repo '[*] ids))))
  825. ;; TODO: use the tree directly
  826. (defn- flatten-tree
  827. [blocks-tree]
  828. (if-let [children (:block/_parent blocks-tree)]
  829. (cons (dissoc blocks-tree :block/_parent) (mapcat flatten-tree children))
  830. [blocks-tree]))
  831. (defn get-block-and-children
  832. [repo block-uuid]
  833. (some-> (d/q
  834. '[:find [(pull ?block ?block-attrs) ...]
  835. :in $ ?id ?block-attrs
  836. :where
  837. [?block :block/uuid ?id]]
  838. (conn/get-db repo)
  839. block-uuid
  840. block-attrs)
  841. first
  842. flatten-tree))
  843. (defn get-file-page
  844. ([file-path]
  845. (get-file-page file-path true))
  846. ([file-path original-name?]
  847. (when-let [repo (state/get-current-repo)]
  848. (when-let [db (conn/get-db repo)]
  849. (some->
  850. (d/q
  851. (if original-name?
  852. '[:find ?page-name
  853. :in $ ?path
  854. :where
  855. [?file :file/path ?path]
  856. [?page :block/file ?file]
  857. [?page :block/original-name ?page-name]]
  858. '[:find ?page-name
  859. :in $ ?path
  860. :where
  861. [?file :file/path ?path]
  862. [?page :block/file ?file]
  863. [?page :block/name ?page-name]])
  864. db file-path)
  865. db-utils/seq-flatten
  866. first)))))
  867. (defn get-page-file
  868. ([page-name]
  869. (get-page-file (state/get-current-repo) page-name))
  870. ([repo page-name]
  871. (some-> (or (db-utils/entity repo [:block/name page-name])
  872. (db-utils/entity repo [:block/original-name page-name]))
  873. :block/file)))
  874. (defn get-block-file-path
  875. [block]
  876. (when-let [page-id (:db/id (:block/page block))]
  877. (:file/path (:block/file (db-utils/entity page-id)))))
  878. (defn get-file-page-id
  879. [file-path]
  880. (when-let [repo (state/get-current-repo)]
  881. (when-let [db (conn/get-db repo)]
  882. (some->
  883. (d/q
  884. '[:find ?page
  885. :in $ ?path
  886. :where
  887. [?file :file/path ?path]
  888. [?page :block/name]
  889. [?page :block/file ?file]]
  890. db file-path)
  891. db-utils/seq-flatten
  892. first))))
  893. (defn get-page
  894. [page-name]
  895. (if-let [id (parse-uuid page-name)]
  896. (db-utils/entity [:block/uuid id])
  897. (db-utils/entity [:block/name (util/page-name-sanity-lc page-name)])))
  898. (defn get-redirect-page-name
  899. "Given any readable page-name, return the exact page-name in db. If page
  900. doesn't exists yet, will return the passed `page-name`. Accepts both
  901. sanitized or unsanitized names.
  902. alias?: if true, alias is allowed to be returned; otherwise, it would be deref."
  903. ([page-name] (get-redirect-page-name page-name false))
  904. ([page-name alias?]
  905. (when page-name
  906. (let [page-name' (util/page-name-sanity-lc page-name)
  907. page-entity (db-utils/entity [:block/name page-name'])]
  908. (cond
  909. alias?
  910. page-name'
  911. (nil? page-entity)
  912. page-name
  913. (page-empty-or-dummy? (state/get-current-repo) (:db/id page-entity))
  914. (let [source-page (get-alias-source-page (state/get-current-repo) page-name')]
  915. (or (when source-page (:block/name source-page))
  916. page-name'))
  917. :else
  918. page-name')))))
  919. (defn get-page-original-name
  920. [page-name]
  921. (when (string? page-name)
  922. (let [page (db-utils/pull [:block/name (util/page-name-sanity-lc page-name)])]
  923. (or (:block/original-name page)
  924. (:block/name page)))))
  925. (defn get-journals-length
  926. []
  927. (let [today (db-utils/date->int (js/Date.))]
  928. (d/q '[:find (count ?page) .
  929. :in $ ?today
  930. :where
  931. [?page :block/journal? true]
  932. [?page :block/journal-day ?journal-day]
  933. [(<= ?journal-day ?today)]]
  934. (conn/get-db (state/get-current-repo))
  935. today)))
  936. (defn get-latest-journals
  937. ([n]
  938. (get-latest-journals (state/get-current-repo) n))
  939. ([repo-url n]
  940. (when (conn/get-db repo-url)
  941. (let [date (js/Date.)
  942. _ (.setDate date (- (.getDate date) (dec n)))
  943. today (db-utils/date->int (js/Date.))]
  944. (->>
  945. (react/q repo-url [:frontend.db.react/journals] {:use-cache? false}
  946. '[:find [(pull ?page [*]) ...]
  947. :in $ ?today
  948. :where
  949. [?page :block/name ?page-name]
  950. [?page :block/journal? true]
  951. [?page :block/journal-day ?journal-day]
  952. [(<= ?journal-day ?today)]]
  953. today)
  954. (react)
  955. (sort-by :block/journal-day)
  956. (reverse)
  957. (take n))))))
  958. ;; get pages that this page referenced
  959. (defn get-page-referenced-pages
  960. [repo page]
  961. (when-let [db (conn/get-db repo)]
  962. (let [page-name (util/safe-page-name-sanity-lc page)
  963. pages (page-alias-set repo page)
  964. page-id (:db/id (db-utils/entity [:block/name page-name]))
  965. ref-pages (d/q
  966. '[:find [?ref-page-name ...]
  967. :in $ ?pages
  968. :where
  969. [(untuple ?pages) [?page ...]]
  970. [?block :block/page ?page]
  971. [?block :block/refs ?ref-page]
  972. [?ref-page :block/name ?ref-page-name]]
  973. db
  974. pages)]
  975. (mapv (fn [page] [page (get-page-alias repo page)]) ref-pages))))
  976. (defn get-page-linked-refs-refed-pages
  977. [repo page]
  978. (when-let [db (conn/get-db repo)]
  979. (->
  980. (d/q
  981. '[:find [?ref-page ...]
  982. :in $ % ?page
  983. :where
  984. [?p :block/name ?page]
  985. [?b :block/path-refs ?p]
  986. [?b :block/refs ?other-p]
  987. [(not= ?p ?other-p)]
  988. [?other-p :block/original-name ?ref-page]]
  989. db
  990. rules
  991. (util/safe-page-name-sanity-lc page))
  992. (distinct))))
  993. ;; Ignore files with empty blocks for now
  994. (defn get-pages-relation
  995. [repo with-journal?]
  996. (when-let [db (conn/get-db repo)]
  997. (let [q (if with-journal?
  998. '[:find ?page ?ref-page-name
  999. :where
  1000. [?p :block/name ?page]
  1001. [?block :block/page ?p]
  1002. [?block :block/refs ?ref-page]
  1003. [?ref-page :block/name ?ref-page-name]]
  1004. '[:find ?page ?ref-page-name
  1005. :where
  1006. [?p :block/journal? false]
  1007. [?p :block/name ?page]
  1008. [?block :block/page ?p]
  1009. [?block :block/refs ?ref-page]
  1010. [?ref-page :block/name ?ref-page-name]])]
  1011. (->>
  1012. (d/q q db)
  1013. (map (fn [[page ref-page-name]]
  1014. [page ref-page-name]))))))
  1015. ;; get pages who mentioned this page
  1016. ;; TODO: use :block/_refs
  1017. (defn get-pages-that-mentioned-page
  1018. [repo page include-journals]
  1019. (when (conn/get-db repo)
  1020. (let [page-id (:db/id (db-utils/entity [:block/name (util/safe-page-name-sanity-lc page)]))
  1021. pages (page-alias-set repo page)
  1022. query-base '[:find ?mentioned-page-name
  1023. :in $ ?pages ?page-name
  1024. :where
  1025. [?block :block/refs ?p]
  1026. [(contains? ?pages ?p)]
  1027. [?block :block/page ?mentioned-page]
  1028. [?mentioned-page :block/name ?mentioned-page-name]]
  1029. query (if include-journals
  1030. query-base
  1031. (conj query-base '[?mentioned-page :block/journal? false]))
  1032. mentioned-pages (->> (react/q repo [:frontend.db.react/page<-pages page-id] {:use-cache? false}
  1033. query
  1034. pages
  1035. page)
  1036. react
  1037. db-utils/seq-flatten)]
  1038. (mapv (fn [page] [page (get-page-alias repo page)]) mentioned-pages))))
  1039. (defn get-page-referenced-blocks-no-cache
  1040. [page-id]
  1041. (when-let [repo (state/get-current-repo)]
  1042. (->>
  1043. (d/q '[:find (pull ?b [*])
  1044. :in $ ?page-id
  1045. :where
  1046. [?b :block/refs ?page-id]]
  1047. (conn/get-db repo)
  1048. page-id)
  1049. (flatten))))
  1050. (defn get-page-referenced-blocks
  1051. ([page]
  1052. (get-page-referenced-blocks (state/get-current-repo) page {:filter? false}))
  1053. ([page options]
  1054. (get-page-referenced-blocks (state/get-current-repo) page options))
  1055. ([repo page options]
  1056. (when repo
  1057. (when (conn/get-db repo)
  1058. (let [page-id (:db/id (db-utils/entity [:block/name (util/safe-page-name-sanity-lc page)]))
  1059. pages (page-alias-set repo page)
  1060. aliases (set/difference pages #{page-id})
  1061. query-result (react/q repo
  1062. [:frontend.db.react/page<-blocks-or-block<-blocks page-id]
  1063. {}
  1064. '[:find [(pull ?block ?block-attrs) ...]
  1065. :in $ [?ref-page ...] ?block-attrs
  1066. :where
  1067. [?block :block/refs ?ref-page]]
  1068. pages
  1069. (butlast block-attrs))
  1070. result (if (not (options :filter?)) (->> query-result
  1071. react
  1072. (remove (fn [block]
  1073. (= page-id (:db/id (:block/page block)))))
  1074. (sort-by-left-recursive)
  1075. db-utils/group-by-page
  1076. (map (fn [[k blocks]]
  1077. (let [k (if (contains? aliases (:db/id k))
  1078. (assoc k :block/alias? true)
  1079. k)]
  1080. [k blocks]))))
  1081. (map (comp :block/original-name :block/page) (->> query-result
  1082. react
  1083. (remove (fn [block]
  1084. (= page-id (:db/id (:block/page block))))) (sort-by-left-recursive))))]
  1085. result)))))
  1086. (defn get-page-referenced-blocks-ids
  1087. "Faster and can be used for pagination later."
  1088. ([page]
  1089. (get-page-referenced-blocks-ids (state/get-current-repo) page))
  1090. ([repo page]
  1091. (when repo
  1092. (when-let [db (conn/get-db repo)]
  1093. (let [pages (page-alias-set repo page)]
  1094. (d/q
  1095. '[:find ?block
  1096. :in $ [?ref-page ...]
  1097. :where
  1098. [?block :block/refs ?ref-page]]
  1099. db
  1100. pages))))))
  1101. (defn get-date-scheduled-or-deadlines
  1102. [journal-title]
  1103. (when-let [date (date/journal-title->int journal-title)]
  1104. (let [future-days (state/get-scheduled-future-days)]
  1105. (when-let [repo (state/get-current-repo)]
  1106. (->> (react/q repo [:custom :scheduled-deadline journal-title] {}
  1107. '[:find [(pull ?block ?block-attrs) ...]
  1108. :in $ ?day ?future ?block-attrs
  1109. :where
  1110. (or
  1111. [?block :block/scheduled ?d]
  1112. [?block :block/deadline ?d])
  1113. [(get-else $ ?block :block/repeated? false) ?repeated]
  1114. [(get-else $ ?block :block/marker "NIL") ?marker]
  1115. [(not= ?marker "DONE")]
  1116. [(not= ?marker "CANCELED")]
  1117. [(not= ?marker "CANCELLED")]
  1118. [(<= ?d ?future)]
  1119. (or-join [?repeated ?d ?day]
  1120. [(true? ?repeated)]
  1121. [(>= ?d ?day)])]
  1122. date
  1123. (+ date future-days)
  1124. block-attrs)
  1125. react
  1126. (sort-by-left-recursive)
  1127. db-utils/group-by-page)))))
  1128. (defn- pattern [name]
  1129. (re-pattern (str "(?i)(^|[^\\[#0-9a-zA-Z]|((^|[^\\[])\\[))"
  1130. (util/regex-escape name)
  1131. "($|[^0-9a-zA-Z])")))
  1132. (defn get-page-unlinked-references
  1133. [page]
  1134. (when-let [repo (state/get-current-repo)]
  1135. (when (conn/get-db repo)
  1136. (let [page (util/safe-page-name-sanity-lc page)
  1137. page-id (:db/id (db-utils/entity [:block/name page]))
  1138. alias-names (get-page-alias-names repo page)
  1139. patterns (->> (conj alias-names page)
  1140. (map pattern))
  1141. filter-fn (fn [datom]
  1142. (some (fn [p]
  1143. (re-find p (->> (:v datom)
  1144. (drawer/remove-logbook))))
  1145. patterns))]
  1146. (->> (react/q repo [:frontend.db.react/page-unlinked-refs page-id]
  1147. {:query-fn (fn [db _tx-report _result]
  1148. (let [ids
  1149. (->> (d/datoms db :aevt :block/content)
  1150. (filter filter-fn)
  1151. (map :e))
  1152. result (d/pull-many db block-attrs ids)]
  1153. (remove (fn [block] (= page-id (:db/id (:block/page block)))) result)))}
  1154. nil)
  1155. react
  1156. (sort-by-left-recursive)
  1157. db-utils/group-by-page)))))
  1158. ;; TODO: Replace recursive queries with datoms index implementation
  1159. ;; see https://github.com/tonsky/datascript/issues/130#issuecomment-169520434
  1160. (defn get-block-referenced-blocks
  1161. ([block-uuid]
  1162. (get-block-referenced-blocks block-uuid {:filter? false}))
  1163. ([block-uuid options]
  1164. (when-let [repo (state/get-current-repo)]
  1165. (when (conn/get-db repo)
  1166. (let [block (db-utils/entity [:block/uuid block-uuid])
  1167. query-result (->> (react/q repo [:frontend.db.react/page<-blocks-or-block<-blocks
  1168. (:db/id block)]
  1169. {:use-cache? false}
  1170. '[:find [(pull ?ref-block ?block-attrs) ...]
  1171. :in $ ?block-uuid ?block-attrs
  1172. :where
  1173. [?block :block/uuid ?block-uuid]
  1174. [?ref-block :block/refs ?block]]
  1175. block-uuid
  1176. block-attrs)
  1177. react
  1178. (sort-by-left-recursive))]
  1179. (if (options :filter?)
  1180. (map (comp :block/original-name :block/page) query-result)
  1181. (db-utils/group-by-page query-result)))))))
  1182. (defn get-block-referenced-blocks-ids
  1183. [block-uuid]
  1184. (when-let [repo (state/get-current-repo)]
  1185. (let [block (db-utils/entity [:block/uuid block-uuid])]
  1186. (->> (react/q repo [:frontend.db.react/block<-block-ids
  1187. (:db/id block)] {}
  1188. '[:find ?ref-block
  1189. :in $ ?block-uuid ?block-attrs
  1190. :where
  1191. [?block :block/uuid ?block-uuid]
  1192. [?ref-block :block/refs ?block]]
  1193. block-uuid
  1194. block-attrs)
  1195. react))))
  1196. (defn get-referenced-blocks-ids
  1197. [page-name-or-block-uuid]
  1198. (if-let [id (parse-uuid (str page-name-or-block-uuid))]
  1199. (get-block-referenced-blocks-ids id)
  1200. (get-page-referenced-blocks-ids page-name-or-block-uuid)))
  1201. (defn journal-page?
  1202. "sanitized page-name only"
  1203. [page-name]
  1204. (:block/journal? (db-utils/entity [:block/name page-name])))
  1205. (defn get-public-pages
  1206. [db]
  1207. (-> (d/q
  1208. '[:find ?p
  1209. :where
  1210. [?p :block/name]
  1211. [?p :block/properties ?properties]
  1212. [(get ?properties :public) ?pub]
  1213. [(= true ?pub)]]
  1214. db)
  1215. (db-utils/seq-flatten)))
  1216. (defn get-public-false-pages
  1217. [db]
  1218. (-> (d/q
  1219. '[:find ?p
  1220. :where
  1221. [?p :block/name]
  1222. [?p :block/properties ?properties]
  1223. [(get ?properties :public) ?pub]
  1224. [(= false ?pub)]]
  1225. db)
  1226. (db-utils/seq-flatten)))
  1227. (defn get-public-false-block-ids
  1228. [db]
  1229. (-> (d/q
  1230. '[:find ?b
  1231. :where
  1232. [?p :block/name]
  1233. [?p :block/properties ?properties]
  1234. [(get ?properties :public) ?pub]
  1235. [(= false ?pub)]
  1236. [?b :block/page ?p]]
  1237. db)
  1238. (db-utils/seq-flatten)))
  1239. (defn get-all-templates
  1240. []
  1241. (let [pred (fn [_db properties]
  1242. (some? (:template properties)))]
  1243. (->> (d/q
  1244. '[:find ?b ?p
  1245. :in $ ?pred
  1246. :where
  1247. [?b :block/properties ?p]
  1248. [(?pred $ ?p)]]
  1249. (conn/get-db)
  1250. pred)
  1251. (map (fn [[e m]]
  1252. [(get m :template) e]))
  1253. (into {}))))
  1254. (defn get-all-properties
  1255. []
  1256. (let [properties (d/q
  1257. '[:find [?p ...]
  1258. :where
  1259. [_ :block/properties ?p]]
  1260. (conn/get-db))
  1261. properties (remove (fn [m] (empty? m)) properties)]
  1262. (->> (map keys properties)
  1263. (apply concat)
  1264. distinct
  1265. (remove #{:id})
  1266. sort)))
  1267. (defn get-property-values
  1268. [property]
  1269. (let [pred (fn [_db properties]
  1270. (get properties property))]
  1271. (->>
  1272. (d/q
  1273. '[:find [?property-val ...]
  1274. :in $ ?pred
  1275. :where
  1276. [_ :block/properties ?p]
  1277. [(?pred $ ?p) ?property-val]]
  1278. (conn/get-db)
  1279. pred)
  1280. (map (fn [x] (if (coll? x) x [x])))
  1281. (apply concat)
  1282. (map str)
  1283. (remove string/blank?)
  1284. (distinct)
  1285. (sort))))
  1286. (defn get-template-by-name
  1287. [name]
  1288. (when (string? name)
  1289. (->> (d/q
  1290. '[:find [(pull ?b [*]) ...]
  1291. :in $ ?name
  1292. :where
  1293. [?b :block/properties ?p]
  1294. [(get ?p :template) ?t]
  1295. [(= ?t ?name)]]
  1296. (conn/get-db)
  1297. name)
  1298. (sort-by :block/name)
  1299. (first))))
  1300. (defonce blocks-count-cache (atom nil))
  1301. (defn blocks-count
  1302. ([]
  1303. (blocks-count true))
  1304. ([cache?]
  1305. (if (and cache? @blocks-count-cache)
  1306. @blocks-count-cache
  1307. (when-let [db (conn/get-db)]
  1308. (let [n (count (d/datoms db :avet :block/uuid))]
  1309. (reset! blocks-count-cache n)
  1310. n)))))
  1311. (defn get-all-referenced-blocks-uuid
  1312. "Get all uuids of blocks with any back link exists."
  1313. []
  1314. (when-let [db (conn/get-db)]
  1315. (d/q '[:find [?refed-uuid ...]
  1316. :where
  1317. ;; ?referee-b is block with ref towards ?refed-b
  1318. [?refed-b :block/uuid ?refed-uuid]
  1319. [?referee-b :block/refs ?refed-b]] db)))
  1320. ;; block/uuid and block/content
  1321. (defn get-all-block-contents
  1322. []
  1323. (when-let [db (conn/get-db)]
  1324. (->> (d/datoms db :avet :block/uuid)
  1325. (map :v)
  1326. (map (fn [id]
  1327. (let [e (db-utils/entity [:block/uuid id])]
  1328. (when (and (not (:block/name e))
  1329. (not (string/blank? (:block/content e))))
  1330. {:db/id (:db/id e)
  1331. :block/uuid id
  1332. :block/page (:db/id (:block/page e))
  1333. :block/content (:block/content e)
  1334. :block/format (:block/format e)}))))
  1335. (remove nil?))))
  1336. (defn get-assets
  1337. [datoms]
  1338. (keep
  1339. (fn [datom]
  1340. (when (= :block/content (:a datom))
  1341. (let [matched (re-seq #"\([./]*/assets/([^)]+)\)" (:v datom))
  1342. matched (get (into [] matched) 0)
  1343. path (get matched 1)]
  1344. (when (and (string? path)
  1345. (not (string/ends-with? path ".js")))
  1346. path))))
  1347. datoms))
  1348. (defn clean-export!
  1349. [db]
  1350. (let [remove? #(contains? #{"me" "recent" "file"} %)
  1351. non-public-pages (get-public-false-pages db)
  1352. non-public-datoms (get-public-false-block-ids db)
  1353. non-public-datom-ids (set (concat non-public-pages non-public-datoms))
  1354. filtered-db (d/filter db
  1355. (fn [_db datom]
  1356. (let [ns (namespace (:a datom))]
  1357. (and (not (remove? ns))
  1358. (not (contains? #{:block/file} (:a datom)))
  1359. (not (contains? non-public-datom-ids (:e datom)))))))
  1360. datoms (d/datoms filtered-db :eavt)
  1361. assets (get-assets datoms)]
  1362. [@(d/conn-from-datoms datoms db-schema/schema) assets]))
  1363. (defn filter-only-public-pages-and-blocks
  1364. [db]
  1365. (let [public-pages (get-public-pages db)]
  1366. (when (seq public-pages)
  1367. (let [public-pages (set public-pages)
  1368. exported-namespace? #(contains? #{"block" "me" "recent"} %)
  1369. filtered-db (d/filter db
  1370. (fn [db datom]
  1371. (let [ns (namespace (:a datom))]
  1372. (and
  1373. (not (contains? #{:block/file} (:a datom)))
  1374. (not= ns "file")
  1375. (or
  1376. (not (exported-namespace? ns))
  1377. (and (= ns "block")
  1378. (or
  1379. (contains? public-pages (:e datom))
  1380. (contains? public-pages (:db/id (:block/page (d/entity db (:e datom))))))))))))
  1381. datoms (d/datoms filtered-db :eavt)
  1382. assets (get-assets datoms)]
  1383. [@(d/conn-from-datoms datoms db-schema/schema) assets]))))
  1384. (defn delete-blocks
  1385. [repo-url files _delete-page?]
  1386. (when (seq files)
  1387. (let [blocks (get-files-blocks repo-url files)]
  1388. (mapv (fn [eid] [:db.fn/retractEntity eid]) blocks))))
  1389. (defn delete-files
  1390. [files]
  1391. (mapv (fn [path] [:db.fn/retractEntity [:file/path path]]) files))
  1392. (defn delete-file-blocks!
  1393. [repo-url path]
  1394. (let [blocks (get-file-blocks repo-url path)]
  1395. (mapv (fn [eid] [:db.fn/retractEntity eid]) blocks)))
  1396. (defn delete-page-blocks
  1397. [repo-url page]
  1398. (when page
  1399. (when-let [db (conn/get-db repo-url)]
  1400. (let [page (db-utils/pull [:block/name (util/page-name-sanity-lc page)])]
  1401. (when page
  1402. (let [datoms (d/datoms db :avet :block/page (:db/id page))
  1403. block-eids (mapv :e datoms)]
  1404. (mapv (fn [eid] [:db.fn/retractEntity eid]) block-eids)))))))
  1405. (defn delete-pages-by-files
  1406. [files]
  1407. (let [pages (->> (mapv get-file-page files)
  1408. (remove nil?))]
  1409. (when (seq pages)
  1410. (mapv (fn [page] [:db.fn/retractEntity [:block/name page]]) (map util/page-name-sanity-lc pages)))))
  1411. (defn set-file-content!
  1412. ([repo path content]
  1413. (set-file-content! repo path content {}))
  1414. ([repo path content opts]
  1415. (when (and repo path)
  1416. (let [tx-data {:file/path path
  1417. :file/content content}]
  1418. (db-utils/transact! repo [tx-data] (merge opts {:skip-refresh? true}))))))
  1419. (defn get-pre-block
  1420. [repo page-id]
  1421. (-> (d/q '[:find (pull ?b [*])
  1422. :in $ ?page
  1423. :where
  1424. [?b :block/page ?page]
  1425. [?b :block/pre-block? true]]
  1426. (conn/get-db repo)
  1427. page-id)
  1428. ffirst))
  1429. (defn get-namespace-pages
  1430. "Accepts both sanitized and unsanitized namespaces"
  1431. [repo namespace]
  1432. (assert (string? namespace))
  1433. (let [namespace (util/page-name-sanity-lc namespace)]
  1434. (d/q
  1435. '[:find [(pull ?c [:db/id :block/name :block/original-name
  1436. :block/namespace
  1437. {:block/file [:db/id :file/path]}]) ...]
  1438. :in $ % ?namespace
  1439. :where
  1440. [?p :block/name ?namespace]
  1441. (namespace ?p ?c)]
  1442. (conn/get-db repo)
  1443. rules
  1444. namespace)))
  1445. (defn- tree [flat-col root]
  1446. (let [sort-fn #(sort-by :block/name %)
  1447. children (group-by :block/namespace flat-col)
  1448. namespace-children (fn namespace-children [parent-id]
  1449. (map (fn [m]
  1450. (assoc m :namespace/children
  1451. (sort-fn (namespace-children {:db/id (:db/id m)}))))
  1452. (sort-fn (get children parent-id))))]
  1453. (namespace-children root)))
  1454. (defn get-namespace-hierarchy
  1455. "Unsanitized namespaces"
  1456. [repo namespace]
  1457. (let [children (get-namespace-pages repo namespace)
  1458. namespace-id (:db/id (db-utils/entity [:block/name (util/page-name-sanity-lc namespace)]))
  1459. root {:db/id namespace-id}
  1460. col (conj children root)]
  1461. (tree col root)))
  1462. (defn get-page-namespace
  1463. [repo page]
  1464. (:block/namespace (db-utils/entity repo [:block/name (util/page-name-sanity-lc page)])))
  1465. (defn get-page-namespace-routes
  1466. [repo page]
  1467. (assert (string? page))
  1468. (when-let [db (conn/get-db repo)]
  1469. (when-not (string/blank? page)
  1470. (let [page (util/page-name-sanity-lc (string/trim page))
  1471. page-exist? (db-utils/entity repo [:block/name page])
  1472. ids (if page-exist?
  1473. '()
  1474. (->> (d/datoms db :aevt :block/name)
  1475. (filter (fn [datom]
  1476. (string/ends-with? (:v datom) (str "/" page))))
  1477. (map :e)))]
  1478. (when (seq ids)
  1479. (db-utils/pull-many repo
  1480. '[:db/id :block/name :block/original-name
  1481. {:block/file [:db/id :file/path]}]
  1482. ids))))))
  1483. (defn get-orphaned-pages
  1484. [{:keys [repo pages empty-ref-f]
  1485. :or {repo (state/get-current-repo)
  1486. empty-ref-f (fn [page] (zero? (count (:block/_refs page))))}}]
  1487. (let [pages (->> (or pages (get-pages repo))
  1488. (remove nil?))
  1489. built-in-pages (set (map string/lower-case default-db/built-in-pages-names))
  1490. orphaned-pages (->>
  1491. (map
  1492. (fn [page]
  1493. (let [name (util/page-name-sanity-lc page)]
  1494. (when-let [page (db-utils/entity [:block/name name])]
  1495. (and
  1496. (empty-ref-f page)
  1497. (or
  1498. (page-empty? repo (:db/id page))
  1499. (let [first-child (first (:block/_left page))
  1500. children (:block/_page page)]
  1501. (and
  1502. first-child
  1503. (= 1 (count children))
  1504. (contains? #{"" "-" "*"} (string/trim (:block/content first-child))))))
  1505. (not (contains? built-in-pages name))
  1506. (not (:block/_namespace page))
  1507. ;; a/b/c might be deleted but a/b/c/d still exists (for backward compatibility)
  1508. (not (and (string/includes? name "/")
  1509. (not (:block/journal? page))))
  1510. page))))
  1511. pages)
  1512. (remove false?)
  1513. (remove nil?))]
  1514. orphaned-pages))