model.cljs 45 KB

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