model.cljs 59 KB

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