model.cljs 52 KB

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